web-dev-qa-db-fra.com

Comment puis-je forcer le composant à effectuer un nouveau rendu avec des crochets dans React?

Considérant ci-dessous exemple de crochets

   import { useState } from 'react';

   function Example() {
       const [count, setCount] = useState(0);

       return (
           <div>
               <p>You clicked {count} times</p>
               <button onClick={() => setCount(count + 1)}>
                  Click me
               </button>
          </div>
        );
     }

Fondamentalement, nous utilisons la méthode this.forceUpdate () pour forcer le composant à effectuer un nouveau rendu immédiatement dans les composants de classe React, comme dans l'exemple ci-dessous.

    class Test extends Component{
        constructor(props){
             super(props);
             this.state = {
                 count:0,
                 count2: 100
             }
             this.setCount = this.setCount.bind(this);//how can I do this with hooks in functional component 
        }
        setCount(){
              let count = this.state.count;
                   count = count+1;
              let count2 = this.state.count2;
                   count2 = count2+1;
              this.setState({count});
              this.forceUpdate();
              //before below setState the component will re-render immediately when this.forceUpdate() is called
              this.setState({count2: count
        }

        render(){
              return (<div>
                   <span>Count: {this.state.count}></span>. 
                   <button onClick={this.setCount}></button>
                 </div>
        }
 }

Mais ma question est: comment puis-je forcer le composant fonctionnel ci-dessus à effectuer un nouveau rendu immédiatement avec des points d'ancrage?

24
Hemadri Dasari

Ceci est possible avec useState ou useReducer, puisque useState utilise useReducer en interne:

const [, updateState] = React.useState();
const forceUpdate = useCallback(() => updateState({}), []);

forceUpdate n'est pas destiné à être utilisé dans des circonstances normales, mais uniquement dans des tests ou d'autres cas en suspens. Cette situation peut être traitée de manière plus conventionnelle.

setCount est un exemple d'utilisation incorrecte de forceUpdate. setState est asynchrone pour des raisons de performances et ne doit pas être forcé à être synchrone simplement parce que les mises à jour d'état n'ont pas été effectuées correctement. Si un état s'appuie sur l'état précédemment défini, vous devez le faire avec fonction de mise à jour ,

Si vous devez définir l'état en fonction de l'état précédent, consultez l'argument ci-dessous pour le programme de mise à jour.

<...>

L’état et les accessoires reçus par la fonction de mise à jour ont la garantie d’être à jour. La sortie du programme de mise à jour est peu fusionnée avec l'état.

setCount n'est peut-être pas un exemple illustratif car son objectif n'est pas clair, mais c'est le cas de la fonction de mise à jour:

setCount(){
  this.setState(({count}) => ({ count: count + 1 }));
  this.setState(({count2}) => ({ count2: count + 1 }));
  this.setState(({count}) => ({ count2: count + 1 }));
}
13
Estus Flask

Votre composant devrait de préférence uniquement dépendre de l'état et des accessoires et il fonctionnera comme prévu. Toutefois, si vous avez réellement besoin d'une fonction pour forcer le composant à restituer, vous pouvez utiliser le hook useState et appeler la fonction lorsque nécessaire.

Exemple

const { useState, useEffect } = React;

function Foo() {
  const [, forceUpdate] = useState();

  useEffect(() => {
    setTimeout(forceUpdate, 2000);
  }, []);

  return <div>{Date.now()}</div>;
}

ReactDOM.render(<Foo />, document.getElementById("root"));
<script src="https://unpkg.com/[email protected]/umd/react.production.min.js"></script>
<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js"></script>

<div id="root"></div>
6
Tholle

Comme les autres l'ont mentionné, useState fonctionne - voici comment mobx-react-lite implémente des mises à jour - vous pourrait faire quelque chose de similaire.

Définir un nouveau crochet, useForceUpdate -

import { useState, useCallback } from 'react'

export function useForceUpdate() {
  const [, setTick] = useState(0);
  const update = useCallback(() => {
    setTick(tick => tick + 1);
  }, [])
  return update;
}

et l'utiliser dans un composant -

const forceUpdate = useForceUpdate();
if (...) {
  forceUpdate(); // force re-render
}

Voir https://github.com/mobxjs/mobx-react-lite/blob/master/src/utils.ts et https://github.com/mobxjs/mobx- react-lite/blob/master/src/useObserver.ts

6
Brian Burns

Vous pouvez simplement définir le useState comme ça:

const [, forceUpdate] = React.useState(0);

Et utilisation: forceUpdate(n => !n)

J'espère que cette aide!

4
Minh Kha

Vous pouvez (ab) utiliser des crochets normaux pour forcer une restitution en profitant du fait que React n'imprime pas de booléens en code JSX

// create a hook
const [forceRerender, setForceRerender] = React.useState(true);

// ...put this line where you want to force a rerender
setForceRerender(!forceRerender);

// ...make sure that {forceRerender} is "visible" in your js code
// ({forceRerender} will not actually be visible since booleans are
// not printed, but updating its value will nonetheless force a
// rerender)
return (
  <div>{forceRerender}</div>
)

3
Fergie

L'option potentielle consiste à forcer la mise à jour uniquement sur un composant spécifique à l'aide de key. La mise à jour de la clé déclenche un rendu du composant (qui n'a pas été mis à jour auparavant)

Par exemple:

const [tableKey, setTableKey] = useState(1);
...

useEffect(() => {
    ...
    setTableKey(tableKey + 1);
}, [tableData]);

...
<DataTable
    key={tableKey}
    data={tableData}/>
0
Idan