2
votes

Comment éviter que le paramètre de fonction useState (pour obtenir les valeurs initiales) ne soit exécuté sur chaque rendu?

Voir l'extrait de getInitialState ci-dessous indiquant que getInitialState est exécuté sur chaque rendu. Même si la valeur renvoyée par celui-ci n'est utilisée que lors du 1er rendu.

Je sais que c'est un comportement Javascript normal. Mais y a-t-il un moyen de l'éviter en utilisant React?

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
function App() {

  function getInitialState() {
    console.log('Executing getInitialState...');
    return({
      foo: 'bar'
    });
  }

  const [myState,setMyState] = React.useState(getInitialState());
  const [myBoolean,setMyBoolean] = React.useState(false);
  
  return(
    <React.Fragment>
      <div>I am App</div>
      <div>My state: {JSON.stringify(myState)}</div>
      <div>My boolean: {JSON.stringify(myBoolean)}</div>
      <button onClick={()=>setMyBoolean((prevState) => !prevState)}>Force Update</button>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));


1 commentaires

pourquoi en avez-vous besoin pour être une fonction plutôt qu'une constante?


4 Réponses :


1
votes

Essayez la React.useMemo avec React.useMemo

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />
function getInitialState() {
  console.log('Executing getInitialState...');
  return {
    foo: 'bar'
  };
}

function App() {
  const getInitial = React.useMemo(() => getInitialState(), []);
  const [myState, setMyState] = React.useState(getInitial);
  const [myBoolean, setMyBoolean] = React.useState(false);

  return (
    <React.Fragment>
      <div> I am App </div>
      <div> My state: {JSON.stringify(myState)} </div>
      <div> My boolean: {JSON.stringify(myBoolean)} </div>
      <button onClick={() => setMyBoolean(prevState => !prevState)}>
        Force Update
      </button>
    </React.Fragment>
  );
}

ReactDOM.render(<App />, document.getElementById('root'));


0 commentaires

4
votes

useState pas la fonction directement dans useState , passez une fonction anonyme pour déclencher la fonction. Reportez-vous au Doc .

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
  function getInitialState() {
    console.log('Executing getInitialState...');
    return({
      foo: 'bar'
    });
  }
  
function App() {

  const [myState,setMyState] = React.useState(()=>getInitialState());
  const [myBoolean,setMyBoolean] = React.useState(false);
  
  return(
    <React.Fragment>
      <div>I am App</div>
      <div>My state: {JSON.stringify(myState)}</div>
      <div>My boolean: {JSON.stringify(myBoolean)}</div>
      <button onClick={()=>setMyBoolean((prevState) => !prevState)}>Force Update</button>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));


3 commentaires

C'est une bonne réponse, mais vous devez expliquer pourquoi et comment cela se produit.


getInitialState() exécutera la fonction à chaque fois mais () => getInitialState() passera la référence de la fonction afin qu'elle soit appelée une fois.


React gérera le useState différemment selon les arguments. Dans votre code, getInitialState() renverra une valeur. Et useState traitera une référence de fonction différemment. S'il s'agit d'une fonction, elle ne sera exécutée que sur le rendu initial



1
votes

Vous devez calculer votre état dans une fonction selon la documentation :

const [myState, setMyState] = useState(getInitialState);

Ou plus court:

const [myState,setMyState] = useState(() => {
  const initialState = getInitialState();
  return initialState;
});

Encore un autre crochet gotcha!


0 commentaires

0
votes

Toutes les bonnes solutions, mes deux cents = la solution la plus courte de Dominic ci-dessus. :)

Vous passez une fonction calculée (le résultat de la fonction est passé à useState) Si vous passez votre fonction, React sait qu'il n'a besoin d'appeler cette fonction que la première fois:

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>
function App() {

  function getInitialState() {
    console.log('Executing getInitialState...');
    return({
      foo: 'bar'
    });
  }

  const [myState,setMyState] = React.useState(getInitialState); // <-- pass the function, not the call to the function (result)
  const [myBoolean,setMyBoolean] = React.useState(false);
  
  return(
    <React.Fragment>
      <div>I am App</div>
      <div>My state: {JSON.stringify(myState)}</div>
      <div>My boolean: {JSON.stringify(myBoolean)}</div>
      <button onClick={()=>setMyBoolean((prevState) => !prevState)}>Force Update</button>
    </React.Fragment>
  );
}

ReactDOM.render(<App/>, document.getElementById('root'));


0 commentaires