Lors de la conversion de composants de classe en composant fonctionnel avec des hooks, je suis tombé sur un scénario que je vais essayer de recréer avec un exemple simple :

J'ai

  • Composant parent en tant que composant de classe ParentClass
  • Composant enfant en tant que composant fonctionnel avec des crochets ChildComponent

Mon composant parent ParentClass passe une fonction de flèche en ligne à ChildComponent en tant qu'accessoire

parent.jsx (qui est un composant de classe)

// inside render method
render () {
  return (
    <div>
    {
      ["component1", "component2"].map((c) => (
        <ChildComponent
          key={c}
          setParentItem={
            (item) => {
              // ... some more logics involving values available in
              // curernt scope only. (for example c)
              this.setState({
                component: c,
                item,
              });
            }
          }
        />
      ))
    }
    </div>
  )
}

child.jsx (qui est un composant fonctionnel)

const [selectedItem, setSelectedItem] = useState({});

/**
  * Here in the dependency array of useEffect
  * eslint-plugin-react asks to add setParentItem as dependency
  * which should be memoized because from the parent component it is
  * passed as an inline arrow function.
  * How can I resolve this?
  */
useEffect(() => {
  setParentItem(selectedItem);    // setParentItem retrieved via props from ParentClass component
}, [selectedItem]);    // Here; adding setParentItem in dependency array will cause infinite render

Comment puis-je mémoriser setParentItem pour qu'après l'avoir ajouté au tableau de dépendances de useEffect dans le ChildComponent, le rendu ne reste pas bloqué dans une boucle infinie ?

Veuillez également consulter le codesandbox pour un exemple de travail.

1
m5khan 8 sept. 2020 à 14:44

1 réponse

Meilleure réponse

Ajoutez-le en tant que champ du composant de classe :


class MyComponent extends React.Component {
  setParentItem = () => {
    // ...
  }

  render() {
    // ...

    <ChildComponent
          setParentItem={this.setParentItem}
    />

    // ...
  }
}

Maintenant, lorsque votre rappel utilise des fermetures, vous ne pouvez pas le faire aussi simplement. Dans ce cas, vous devez modifier votre code pour qu'il ne crée pas de fermetures. C'est à dire. faire ChildComponent pour transmettre la valeur :


function ChildComponent({ setParentItem, component, ...props }) {
  // ...
  setParentItem(selectedItem, component);
}

1
Алексей Мартинкевич 8 sept. 2020 à 11:52