ライフサイクルメソッド内で状態が変更されたときに再レンダリングされるコンポーネント内で、Apolloクライアントの<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に渡すことはできません。これを解決するためにタイマーを導入したりChildComponent
を複雑にしたくありません-この複雑さやデータ取得の問題について知る必要はありません。
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();
Queryコンポーネントは必ずしもこのParentComponent
の中にある必要はないようです。
その場合は、ChildComponent
に結果がなくても他のものをレンダリングできるため、Queryコンポーネントを上に移動します。そして、 query.refetch
メソッドにアクセスできます。
例ではgraphql
hocを追加しましたが、<ParentComponent />
の周りでQueryコンポーネントを使用できることに注意してください。
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);
親コンポーネントで再取得できますか?親コンポーネントが更新を取得すると、フェッチをトリガーするかどうかを評価できます。
次のように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番目の方法では、子供に何かを渡す必要がありますが、これはそれほど悪いことではありません。
約束どおり、ここに私のハッキングの回避策があります
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>
)
}
}