Apollo学习笔记(3)mutations
1、Mutation Component
Apollo-client修改数据使用的是Mutation component.Mutation component 和Query component设计非常的相似,都是render prop模型。
Mutation组件接受的参数:第一个是mutation接受的和Query相对是mutation document,用gql包含字符串转义得到。
第二个是children:包含一个function ,告诉组件提交修改后返回的组件:包含loading, error, called, and data等参数。
示例:
import gql from "graphql-tag";
import { Mutation } from "react-apollo";
const ADD_TODO = gql`
mutation AddTodo($type: String!) {
addTodo(type: $type) {
id
type
}
}
`;
const AddTodo = () => {
let input;
return (
<Mutation mutation={ADD_TODO}>
{(addTodo, { data }) => (
<div>
<form
onSubmit={e => {
e.preventDefault();
addTodo({ variables: { type: input.value } });
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
)}
</Mutation>
);
};
mutation function的第一个参数是addTodo,代表这个mutation function 本身。Mutation的props中除了可以传入mutation之外,还可以传入的是variables, optimisticResponse, refetchQueries, 和update。注意这里,我们传入variables是通过addTodo传入而不是直接在props中传入,其效果是一样的。
<input ref={node=>{input=node;}}/>ref指向的是input标签本身,node代指本节点,input=node,代表input指向了《input》标签节点,这样input.value就代表输入框的值。
mutation function的第二个参数是{data,loading,error,called}等,如果不希望使用第二个参数,可以在Mutation component 的props上传入ignoreResults;
通过上述的修改操作,你会发现TODO列表并没有把我们刚刚增加的todo显示出来,这是由于Query组件监听的是cache,由于cache没有更新,仅仅是服务端更新了,所以页面没有更新。
2、更新缓存
更新缓存,我们需要用到update props
update 接受一个function,第一个参数代表cache,cache有cache.readQuery和cache.writeQuery可以让我们更新缓存,还有cache.readFragment, cache.writeFragment, 和 cache.writeData等。
第二个数据代表mutation函数的结果。如果执行乐观更新的话将会更新两次,一次是mutation 函数的结果,另一次是真实的数据。
示例:
const AddTodo = () => {
let input;
return (
<Mutation
mutation={ADD_TODO}
update={(cache, { data: { addTodo } }) => {
const { todos } = cache.readQuery({ query: GET_TODOS });
cache.writeQuery({
query: GET_TODOS,
data: { todos: todos.concat([addTodo]) }
});
}}
>
{addTodo => (
<div>
<form
onSubmit={e => {
e.preventDefault();
addTodo({ variables: { type: input.value } });
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
)}
</Mutation>
);
};
第一步:我们从缓存中通过cache.readQurey读取相关的数据todos。
第二步:我们将mutation生成的新的todo与第一步得到的todos连接在一起,并且通过writeQuery写回到对应的Qurey中。
现在我们的将会把我们新增的todo显示出来。
并不是所有的修改都需要update参数的,如果你仅需要更新一个item,那么你可以返回id和对应的属性,Apollo-client将会帮助你完成更新。
示例:
const UPDATE_TODO = gql`
mutation UpdateTodo($id: String!, $type: String!) {
updateTodo(id: $id, type: $type) {
id
type
}
}
`;
const Todos = () => (
<Query query={GET_TODOS}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.todos.map(({ id, type }) => {
let input;
return (
<Mutation mutation={UPDATE_TODO} key={id}>
{updateTodo => (
<div>
<p>{type}</p>
<form
onSubmit={e => {
e.preventDefault();
updateTodo({ variables: { id, type: input.value } });
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Update Todo</button>
</form>
</div>
)}
</Mutation>
);
});
}}
</Query>
);
3、loading和error state
我们可以通过loading和error管理mutation的状态,此外还有called代表mutation function是否被调用了。
在Mutation组件上,还有onCompleted和onError等用于监视组件的行为。
4、Mutation api概览
utation组件接受以下props。只是mutation而且children是必需的。
mutation:DocumentNode- 一个GraphQL变异文档解析为AST
graphql-tag。需要 children:( mutate:Function,result:MutationResult)=> React.ReactNode- 一种允许您从UI触发变异的功能。需要
variables:{[key:string]:any}- 包含您的突变需要执行的所有变量的对象
update:( cache:DataProxy,mutationResult:FetchResult)- 用于在发生突变后更新缓存的函数
ignoreResults:布尔值- 如果为true,则
data渲染道具功能上的属性不会随突变结果一起更新。 optimisticResponse:对象- 在结果从服务器返回之前提供mutation result
refetchQueries:(mutationResult:FetchResult)=> Array <{query:DocumentNode,variables?:TVariables} | 字符串>- 一个函数,允许您指定在发生突变后要重新获取的查询
awaitRefetchQueries:布尔值- 作为一部分重新获取的查询
refetchQueries是异步处理的,并且在变异完成(解决)之前不会等待。将此设置为true将确保在认为完成变异之前完成重新获取的查询。false默认。 onCompleted:(数据:TData)=>无效- 一旦您的变异成功完成,就会执行回调
onError:(错误:ApolloError)=>无效- 发生错误时执行的回调
context:记录<string,any>- Mutation组件与网络接口(Apollo Link)之间的共享上下文。用于从道具设置标题或将信息发送到
requestApollo Boost 的功能。
render prop 功能
渲染,你传递给道具功能children的道具Mutation被调用的mutate函数,并与mutation结果的对象。该mutate功能是您从UI触发变异的方式。该对象包含您的变异结果,加上加载和错误状态。
变异功能:
mutate:(选项?:MutationOptions)=>承诺- 用于从UI触发变异的函数。您可以选择通过
variables,optimisticResponse,refetchQueries,和update作为选项,这将覆盖传递到任何道具Mutation组件。该函数返回一个履行变异结果的承诺。
变异结果:
data:TData- 您的突变返回的数据。如果
ignoreResults是真的,它可以是未定义的。 loading:布尔值- 一个布尔值,表示您的突变是否在飞行中
error:ApolloError- 突变返回的任何错误
called:布尔值- 一个布尔值,指示是否已调用mutate函数
client:ApolloClient- 你的
ApolloClient实例。用于在更新函数的上下文之外调用缓存方法,例如client.writeData和client.readQuery。
全部代码:
const client = new ApolloClient({
uri: "https://8v9r9kpn7q.lp.gql.zone/graphql"
});
const GET_TODOS = gql`
{
todos {
id
type
}
}
`;
const UPDATE_TODO = gql`
mutation UpdateTodo($id: String!, $type: String!) {
updateTodo(id: $id, type: $type) {
id
type
}
}
`;
const Todos = () => (
<Query query={GET_TODOS}>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return data.todos.map(({ id, type }) => {
let input;
return (
<Mutation mutation={UPDATE_TODO} key={id}>
{updateTodo =>(
<div key={id}>
<p>{type}</p>
<form
onSubmit={e => {
e.preventDefault();
updateTodo({ variables: { id, type: input.value } });
// if (!input.value.trim()) {
// return;
// }
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Update Todo</button>
</form>
</div>
);}
</Mutation>
);
});
}}
</Query>
);
const ADD_TODO = gql`
mutation AddTodo($type: String!) {
addTodo(type: $type) {
id
type
}
}
`;
const AddTodo = () => {
let input;
return (
<Mutation
mutation={ADD_TODO}
update={(cache, { data: { addTodo } }) => {
const { todos } = cache.readQuery({ query: GET_TODOS });
cache.writeQuery({
query: GET_TODOS,
data: { todos: todos.concat([addTodo]) }
});
}}
>
{(addTodo, { data }) => (
<div>
<form
onSubmit={e => {
e.preventDefault();
addTodo({ variables: { type: input.value } });
input.value = "";
}}
>
<input
ref={node => {
input = node;
}}
/>
<button type="submit">Add Todo</button>
</form>
</div>
)}
</Mutation>
);
};
const App = () => (
<ApolloProvider client={client}>
<div>
<h2>Building Mutation components 🚀</h2>
<AddTodo />
<Todos />
</div>
</ApolloProvider>
);
ReactDOM.render(
<App />,
document.getElementById('root'));
registerServiceWorker();
浙公网安备 33010602011771号