web-dev-qa-db-ja.com

親コンポーネントが再レンダリングされるときにApollo Queryコンポーネントに強制的にクエリを再実行させる方法

ライフサイクルメソッド内で状態が変更されたときに再レンダリングされるコンポーネント内で、Apolloクライアントの<Query>を使用しています。データが変更されたことがわかっているため、<Query>コンポーネントにクエリを再実行させたいと思います。クエリコンポーネントは、クエリを再実行する前に無効にする必要があるキャッシュを使用しているようです。

親コンポーネントのレンダープロップからのrefetchコールバックをキャッシュする不安定な回避策を使用していますが、間違っていると感じています。誰かが興味を持っている場合は、回答に私のアプローチを掲載します。

私のコードはこのようなものです。クエリからloadingerrorの処理を削除し、簡潔にするためにその他の詳細を削除しました。

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を複雑にしたくありません-この複雑さやデータ取得の問題について知る必要はありません。

11
Andrei R

fetchPolicy属性で解決したほぼ同様の状況がありました。

<Query fetchPolicy="no-cache" ...

タスクは、リスト項目をクリックしてサーバーから詳細をロードすることでした。

また、クエリの再フェッチを強制するアクション(詳細の変更など)を追加する場合は、最初にrefetchthis.refetchに割り当てました。

<Query fetchPolicy="no-cache" query={GET_ACCOUNT_DETAILS} variables=... }}>
  {({ data: { account }, loading, refetch }) => {
  this.refetch = refetch;
...

そして、再フェッチを実行したかった特定のアクションで、私は以下を呼び出しました:

this.refetch();
4
Saro

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番目の方法では、子供に何かを渡す必要がありますが、これはそれほど悪いことではありません。

1
leogoesger

約束どおり、ここに私のハッキングの回避策があります

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>
    )
  }
}
0
Andrei R