本系列文以制作专案为主轴,纪录小弟学习React以及GrahQL的过程。主要是记下重点步骤以及我觉得需要记忆的部分,有觉得不明确的地方还请留言多多指教。
Apollo Client 在进行 query 後会在 client 端建立 cache,而在 mutation 後若希望画面更新到最新资讯,Apollo Client 自有一套更新的方法,在介绍方法前先用 dev tools 让 cache 可视化,并介绍一下 Cache 的构造。
Apollo 提供的工具,安装後在网页工具中找到 Apollo
可以在 Cache 标签看到目前的 cache 内容。
在Cache中可以看到像是 List:6 这样的名称,这是 InMemoryCache 这个方法帮每笔资料建立的
cache id,构造会像这样:
[__typename]:[id]
这个 __typename 就是根据 Server 的 schema 建立的,Apollo Client 在 Query 时会自己偷偷请求这个栏位,可以在Queries标签底下看到:
而每笔资料有了独特id後就表列在 cache 中,至於资料间的关联会以 __ref 参照:
要在mutation後触发单一笔 cache 资料的更新,方法是在 mutation 的回完值中带上目标的 id 以及更新的栏位,以下用editTodo为例。
先补上 Server端的 schema:
editTodo(todoId: Int, name: String): Todo!
以及 reducer:
editTodo: (parent, args, context) => {
return context.prisma.todo.update({
where: { id: args.todoId },
data: {
name: args.name,
},
});
}
Client 端 Mutation 请求:
const EDIT_TODO = gql`
mutation EditTodo($name: String!, $todoId: Int!) {
editTodo(name: $name, todoId: $todoId) {
id //目标的id
name //更新的栏位
}
}
`;
宣告 editTodo方法:
const [editTodo] = useMutation(EDIT_TODO);
这样当 editTodo 被执行後如果成功更新并回传,Apollo Client就会找到对应的 Todo:id 资料并更新 name 栏位,同时通知 React 刷新画面。
如果新增了资料,在 Cache 中没有对应的 id 可以触发更新,就要用 cache.modify 方法。
以 addList 方法为例,先补上 server schema 跟 resolvers。
addList(listTitle: String): List!
addList: (parent, args, context) => {
return context.prisma.list.create({
data: {
title: args.listTitle,
},
});
}
Client 端 Mutation 请求:
const ADD_LIST = gql`
mutation AddList($listTitle: String!) {
addList(listTitle: $listTitle) {
id
}
}
`;
宣告 addList 方法:
const [addList] = useMutation(ADD_LIST, {
update(cache, { data: { addList } }) {
cache.modify({
fields: {
lists(
existingLists = [] //预设为空阵列
) {
const newListRef = cache.writeFragment({
data: addList,
fragment: gql`
fragment NewList on List {
id
title
}
`,
});
return [...existingLists, newListRef];
},
},
});
},
});
事情变得复杂了,一层层解释吧。
useMutation 可接收两个参数,第一个就是 gql指令,而第二个则是 option 物件。
option 中包含很多方法,像是 onError,onCompleted 等,可以更精确的操控 mutation 过程。
而 option 其中的 update 用於定义 mutation 完成,收到回传值後操作 cache 的动作。
update( cache , respondedData ){...}
从 update 可以存取 cache 实例以及回传的资讯,范例中 { data: { addList } } 只是利用解构赋值将回传的 List 物件直接取出来用。
cache.modify 用於编辑已存在的 cache 资料,主要用以下参数指定编辑目标:
fields: {
lists(){...}
}
用於编辑目标 cache 的 lists 栏位。cache.modify 用 id 与 fields 指定好编辑目标後就撰写Modifiers实作编辑动作。
Modifier 方法包含两个参数,第一个是目标栏位的目前值,第二个是一组 helper function 工具。
以 lists为例的话:
lists( existingLists = [] , {readField}) {...}
在这个 Modifier 里,首先要新增一个 newList cache,并将 newList 的参照添加到现有的 lists 阵列中。
const newListRef = cache.writeFragment({
data: addList,
fragment: gql`
fragment NewList on List {
id
title
}
`,
});
先说说 Fragment ,这是 GraphQL 语法的一部分,主要用来打包对象Type 的一组 Fields,并可重复利用。
fragment NewList on List {
id
title
}
NewList 只包含了 List 的 id 跟 title 栏位。
而 writeFragment 可以用 fragment 决定要写入 cache 的 资料结构,并将 data 中的资料写入 Cache,并回传新的 cache 的 __ref。
Modifier 的回传值会成为 cache.modify 对象的新值,这边将新取得的 __ref 加入 lists 阵列回传,就成了新增後的 lists。
这次先简单示范两个常用的 cache 编辑方式,还有很多应用可以研究。
连续 30 天不中断每天上传一支教学影片,教你如何用 React 加上 Firebase 打造社群...
前言 从小到大我们都听过这样的一句话: 工欲善其事,必先利其器 ------ 书上写的 在我们开始执...
示范一个简单的功能,在网页上有一个搜寻功能,搜寻栏右边有执行的图示。 标准的做法就是输入文字後,按下...
学习目标 object 物件、while 回圈、密码检验程序 object 物件 可以存放许多key...
环境:linux使用者直接用终端机即可,windows使用者可用WSL或是建一个linux的虚拟机 ...