我们正在使用Apollo Client构建离线的第一个React Native Application。目前我正在尝试在离线时直接更新Apollo Cache以乐观地更新UI。由于我们离线,我们不会尝试触发突变,直到连接是“在线”,但希望用户界面在突然被解雇之前反映这些变化,同时仍处于脱机状态。我们正在使用http://dev.apollodata.com/core/read-and-write.html#writequery-and-writefragment中的readQuery / writeQuery API函数。并且能够通过Reacotron查看正在更新的缓存,但是,UI不会随着此缓存更新的结果而更新。
const newItemQuantity = existingItemQty + 1;
const data = this.props.client.readQuery({ query: getCart, variables: { referenceNumber: this.props.activeCartId } });
data.cart.items[itemIndex].quantity = newItemQuantity;
this.props.client.writeQuery({ query: getCart, data });
答案 0 :(得分:2)
只是为了节省别人的时间。解决方案就是以不变的方式使用数据。完全同意answer,但对我来说,我做错了其他事情,将在此处显示。我遵循了tutorial,并在完成本教程后更新缓存工作正常。因此,我尝试在自己的应用程序中应用这些知识,但是即使我做了本教程中显示的所有类似操作,该更新也无法正常工作。
这是我使用状态在render方法中访问数据来更新数据的方法:
// ... imports
export const GET_POSTS = gql`
query getPosts {
posts {
id
title
}
}
`
class PostList extends Component {
constructor(props) {
super(props)
this.state = {
posts: props.posts
}
}
render() {
const postItems = this.state.posts.map(item => <PostItem key={item.id} post={item} />)
return (
<div className="post-list">
{postItems}
</div>
)
}
}
const PostListQuery = () => {
return (
<Query query={GET_POSTS}>
{({ loading, error, data }) => {
if (loading) {
return (<div>Loading...</div>)
}
if (error) {
console.error(error)
}
return (<PostList posts={data.posts} />)
}}
</Query>
)
}
export default PostListQuery
解决方案是直接访问日期,而不使用状态。看到这里:
class PostList extends Component {
render() {
// use posts directly here in render to make `cache.writeQuery` work. Don't set it via state
const { posts } = this.props
const postItems = posts.map(item => <PostItem key={item.id} post={item} />)
return (
<div className="post-list">
{postItems}
</div>
)
}
}
为了完整起见,这是我用来添加新帖子和更新缓存的输入:
import React, { useState, useRef } from 'react'
import gql from 'graphql-tag'
import { Mutation } from 'react-apollo'
import { GET_POSTS } from './PostList'
const ADD_POST = gql`
mutation ($post: String!) {
insert_posts(objects:{title: $post}) {
affected_rows
returning {
id
title
}
}
}
`
const PostInput = () => {
const input = useRef(null)
const [postInput, setPostInput] = useState('')
const updateCache = (cache, {data}) => {
// Fetch the posts from the cache
const existingPosts = cache.readQuery({
query: GET_POSTS
})
// Add the new post to the cache
const newPost = data.insert_posts.returning[0]
// Use writeQuery to update the cache and update ui
cache.writeQuery({
query: GET_POSTS,
data: {
posts: [
newPost, ...existingPosts.posts
]
}
})
}
const resetInput = () => {
setPostInput('')
input.current.focus()
}
return (
<Mutation mutation={ADD_POST} update={updateCache} onCompleted={resetInput}>
{(addPost, { loading, data }) => {
return (
<form onSubmit={(e) => {
e.preventDefault()
addPost({variables: { post: postInput }})
}}>
<input
value={postInput}
placeholder="Enter a new post"
disabled={loading}
ref={input}
onChange={e => (setPostInput(e.target.value))}
/>
</form>
)
}}
</Mutation>
)
}
export default PostInput
答案 1 :(得分:0)
如果查看文档示例,您将看到它们以不可变的方式使用数据。传递给写入查询的数据属性与读取的对象不是同一个对象。 Apollo不太可能支持对此对象进行变换,因为它不会非常有效地检测您修改的属性,而无需在之前/之后进行深度复制和数据比较。
const query = gql`
query MyTodoAppQuery {
todos {
id
text
completed
}
}
`;
const data = client.readQuery({ query });
const myNewTodo = {
id: '6',
text: 'Start using Apollo Client.',
completed: false,
};
client.writeQuery({
query,
data: {
todos: [...data.todos, myNewTodo],
},
});
因此,您应该在不改变数据的情况下尝试相同的代码。您可以使用set
的{{1}}来帮助您
lodash/fp