我在组件中使用Apollo Client的<Query>
,该组件在生命周期方法中更改状态时会重新呈现。我希望我的<Query>
组件重新运行查询,因为我知道数据已更改。
看来查询组件正在使用一个缓存,该缓存需要在重新运行查询之前无效。
我正在使用一种怪异的解决方法,该方法可将来自呈现器道具的refetch
回调缓存在父组件中,但是感觉不对。如果有人感兴趣,我会在答案中张贴我的方法。
我的代码看起来像这样。我从查询中删除了loading
和error
处理,为了简洁起见,还删除了其他一些细节。
class ParentComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.refetchId !== prevProps.refetchId) {
const otherData = this.processData() // do something
this.setState({otherData}) // this forces component to reload
}
}
render() {
const { otherData } = this.state
return (
<Query query={MY_QUERY}>
{({ data }) => {
return <ChildComponent gqlData={data} stateData={otherData} />
}}
</Query>
)
}
}
如何强制<Query>
获取新数据以传递给<ChildComponent>
?
即使ParentComponent
在道具或状态改变时重新渲染,Query
也不会重新运行。 ChildComponent
获得更新的stateData
道具,但是拥有陈旧的gqlData
道具。据我了解,Apollo的查询缓存需要无效,但我不确定。
请注意,将refetch
传递给ChildComponent并不是答案,因为它仅显示GraphQL的信息,并且不知道何时重新提取。我不想引入计时器或使ChildComponent
复杂化来解决此问题-它不需要了解这种复杂性或数据获取问题。
答案 0 :(得分:2)
在我看来,查询组件不一定必须位于此ParentComponent
中。
在那种情况下,我将向上移动Query组件,因为在ChildComponent
中没有结果的情况下,我仍然可以渲染其他内容。然后,我将可以访问query.refetch
方法。
请注意,在示例中,我添加了graphql
临时对象,但是您仍然可以在<ParentComponent />
周围使用查询组件。
class ParentComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.refetchId !== prevProps.refetchId) {
const otherData = this.processData() // do something
// won't need this anymore, since refetch will cause the Parent component to rerender)
// this.setState({otherData}) // this forces component to reload
this.props.myQuery.refetch(); // >>> Refetch here!
}
}
render() {
const {
otherData
} = this.state;
return <ChildComponent gqlData={this.props.myQuery} stateData={otherData} />;
}
}
export graphql(MY_QUERY, {
name: 'myQuery'
})(ParentComponent);
答案 1 :(得分:1)
您可以重新获取父组件吗?父组件获得更新后,您就可以评估是否触发提取。
我没有使用Query
来完成此操作,如下所示:
class ParentComp extends React.Component {
lifeCycleHook(e) { //here
// call your query here
this.props.someQuery()
}
render() {
return (
<div>
<Child Comp data={this.props.data.key}> //child would only need to render data
</div>
);
}
}
export default graphql(someQuery)(SongCreate);
因此您可以随时触发获取。在这种情况下,您可以将查询作为prop
。
对于您的情况,您可以使用export default graphql(addSongQuery)(SongCreate);
将查询放入属性。然后在您的生命周期钩子DidUpdate
中调用它。
另一种选择是在查询上使用refetch
。
<Query
query={GET_DOG_PHOTO}
variables={{ breed }}
skip={!breed}
>
{({ loading, error, data, refetch }) => {
if (loading) return null;
if (error) return `Error!: ${error}`;
return (
<div>
<img
src={data.dog.displayImage}
style={{ height: 100, width: 100 }}
/>
<button onClick={() => refetch()}>Refetch!</button>
</div>
);
}}
</Query>
第二种方法将要求您将某些信息传递给孩子,这并不是真的那么糟糕。
答案 2 :(得分:1)
我遇到了类似的情况,可以通过fetchPolicy
属性来解决:
<Query fetchPolicy="no-cache"
...
任务是通过单击列表项从服务器加载一些详细信息。
如果我想添加一个操作来强制重新获取查询(例如修改详细信息),我首先将refetch
分配给this.refetch
:
<Query fetchPolicy="no-cache" query={GET_ACCOUNT_DETAILS} variables=... }}>
{({ data: { account }, loading, refetch }) => {
this.refetch = refetch;
...
在我希望进行重新提取的特定操作中,我致电:
this.refetch();
答案 3 :(得分:0)
如所承诺的,这是我的解决方法
class ParentComponent extends React.Component {
componentDidUpdate(prevProps) {
if (this.props.refetchId !== prevProps.refetchId) {
const otherData = this.processData() // do something
this.setState({otherData})
if (this.refetch) {
this.refetch()
}
}
}
render() {
const { otherData } = this.state
const setRefetch = refetch => {this.refetch = refetch}
return (
<Query query={MY_QUERY}>
{({ data, refetch }) => {
setRefetch(refetch)
return <ChildComponent gqlData={data} stateData={otherData} />
}}
</Query>
)
}
}
答案 4 :(得分:0)
除了上面已经接受的答案外,还有两种方法可以实现这一目标。
如果只需要从graphql服务器获取数据以在每次安装组件时生成列表,则可以使用以下选项:
fetchPolicy="no-cache"
export default defineComponent({
setup() {
const { result, loading, error } = useMyQuery(
() => {
return { date: new Date() }
},
{
pollInterval: 15 * 60 * 1000, // refresh data every 15 min
fetchPolicy: 'no-cache',
}
)
refetch()
方法,同时将缓存保留在适当的位置:export default defineComponent({
setup() {
const { result, loading, error}, refetch } = useMyQuery(
() => {
return { date: new Date() }
},
{
pollInterval: 15 * 60 * 1000, // refresh data every 15 min
}
)
if (!loading.value) void refetch()