web-dev-qa-db-fra.com

Comment forcer le composant Apollo Query à réexécuter une requête lorsque le composant parent est restitué

J'utilise le <Query> d'Apollo Client dans un composant qui est rendu à nouveau lorsque l'état est modifié dans une méthode de cycle de vie. Je souhaite que mon composant <Query> ré-exécute la requête car je sais que les données ont été modifiées .. Il apparaît que le composant Query utilise un cache qui doit être invalidé avant que la requête ne soit réexécutée.

J'utilise une solution de contournement qui met en cache le rappel refetch à partir de l'accessoire de rendu dans le composant parent, mais cela semble faux. Je posterai mon approche dans les réponses si quelqu'un est intéressé.

Mon code ressemble à quelque chose comme ça. J'ai supprimé les manipulations loading et error de la requête ainsi que certains autres détails par souci de concision.

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>
    )
  }
}

Comment forcer <Query> à récupérer de nouvelles données à transmettre à <ChildComponent>?  

Même si ParentComponent effectue un nouveau rendu lorsque les accessoires ou les états changent, Query ne s'exécute pas à nouveau. ChildComponent obtient une prop stateData mise à jour, mais a une prop gqlData obsolète. Si j'ai bien compris, le cache de requêtes d'Apollo doit être invalidé, mais je ne suis pas sûr.

Notez que transmettre refetch à ChildComponent n’est pas la solution car il n’affiche que les informations provenant de GraphQL et ne sait pas quand récupérer. Je ne veux pas introduire de timers ni autrement compliquer ChildComponent pour résoudre ceci - il n'a pas besoin de connaître cette complexité ni les problèmes d'extraction de données.

5
Andrei R

Il me semble que le composant Query n'a pas nécessairement besoin d'être dans cette ParentComponent.

Dans ce cas, je déplacerais le composant de requête vers le haut, étant donné que je serais toujours capable de restituer d'autres éléments sans avoir de résultats dans la variable ChildComponent. Et puis j'aurais accès à la méthode query.refetch .

Notez que dans l'exemple, j'ai ajouté graphql hoc, mais vous pouvez toujours utiliser le composant Query autour de <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);
2

Pourriez-vous récupérer dans le composant parent? Une fois que le composant parent a obtenu une mise à jour, vous pouvez alors déterminer s'il faut déclencher une extraction ou non.

Je l'ai fait sans utiliser Query comme ceci: 

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);

Ainsi, vous pouvez déclencher votre recherche à tout moment. Vous pouvez obtenir la requête sous la forme prop dans ce cas.

Pour votre cas, vous mettriez votre requête dans un accessoire utilisant export default graphql(addSongQuery)(SongCreate);. Ensuite, appelez-le dans votre cycle de vie crochet_sans DidUpdate

Une autre option consiste à utiliser refetch sur une requête.

<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>

La deuxième méthode exigerait que vous transmettiez quelque chose à votre enfant, ce qui n’est pas si grave.

1
leogoesger