web-dev-qa-db-fra.com

Est-ce que le nouveau React Context API trigger re-rend?

J'ai essayé de comprendre la nouvelle React Context API et je jouais avec. Je voulais juste vérifier un cas simple - ce que tout restitue lorsque les données d'un fournisseur sont mises à jour.

Cochez ce petit exemple sur Codesandbox

Donc, dans mon exemple, j'ai un composant App - qui a quelque chose comme ça -

this.state = {
  number - A random number
  text - A static text
} 

Je crée un nouveau contexte React d'ici contenant number et text depuis l'état et passe les valeurs à deux consommateurs Number et Text.

Donc, mon hypothèse est que si le nombre aléatoire est mis à jour, cela changera le contexte et les deux composants devraient déclencher un nouveau rendu.

Mais en réalité, la valeur est en cours de mise à jour mais aucun rendu n'est en cours.

Donc, ma question -

  1. Les mises à jour du contexte ne sont-elles pas propagées via les rendus ususaux? Comme je ne peux pas voir mes journaux/changements de couleur lorsque le contexte change.

  2. Tous les consommateurs de ce fournisseur sont-ils mis à jour ou non?

18
Sachin

Les mises à jour du contexte ne sont-elles pas propagées via les rendus ususaux? Comme je ne peux pas voir mes journaux/changements de couleur lorsque le contexte change.

Les mises à jour des valeurs de contexte ne déclenchent pas de nouveau rendu pour tous les enfants du fournisseur, mais uniquement les composants qui sont rendus à partir du consommateur, donc dans votre cas, bien que le composant numérique contienne le consommateur, le composant numérique n'est pas restitué , plutôt juste la fonction de rendu dans le consommateur et donc la valeur change lors des mises à jour de contexte. De cette façon, il est assez performant car il ne déclenche pas de restitutions pour tous ses enfants.

Tous les consommateurs de ce fournisseur sont-ils mis à jour ou non?

Tous les consommateurs de ce fournisseur passeront par un cycle de mise à jour, mais leur nouveau rendu est décidé par la comparaison de DOM virtuel réactif. Une démonstration de cela, vous pouvez voir dans la console pour cela bac à sable

[~ # ~] modifier [~ # ~]

Ce que vous devez vous assurer, c'est que les composants sont rendus en tant qu'enfants du composant ContextProvider et que vous lui passez des gestionnaires au lieu de les rendre en ligne et de mettre à jour l'état de ContextProvider car cela déclenchera un nouveau rendu de tous les composants qui se trouvent dans le ContextProvider

Utilisation performante

App.js

  render() {
    return (
      <AppContext.Provider
        value={{ ...this.state, updateNumber: this.updateNumber }}
      >
        {this.props.children}
      </AppContext.Provider>
    );
  }

index.js

class Data extends React.Component {
  render() {
    return (
      <div>
        <h1>Welcome to React</h1>
        <Number />
        <Text />
        <TestComp />
        <AppContext.Consumer>
          {({ updateNumber }) => (
            <button onClick={updateNumber}>Change Number </button>
          )}
        </AppContext.Consumer>
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <App>
    <Data />
  </App>,
  rootElement
);

Utilisation moins performante

App.js

class App extends Component {
  constructor() {
    super();
    this.state = {
      number: Math.random() * 100,
      text: "testing context api"
    };
  }

  updateNumber = () => {
    const randomNumber = Math.random() * 100;
    this.setState({ number: randomNumber });
  };

  render() {
    return (
      <AppContext.Provider value={this.state}>
        <div>
          <h1>Welcome to React</h1>
          <Number />
          <Text />
          <TestComp />
          <button onClick={this.updateNumber}>Change Number </button>
        </div>
      </AppContext.Provider>
    );
  }
}
21
Shubham Khatri

Voici une mise à jour de vos questions basée sur le crochet useContext :

const value = useContext(MyContext)

Lorsque le <MyContext.Provider> Le plus proche au-dessus des composants est mis à jour, ce hook déclenchera un nouveau rendu avec le dernier contexte value transmis à ce fournisseur MyContext. Même si un ancêtre utilise React.memo Ou shouldComponentUpdate, un nouveau rendu se produira toujours en commençant sur le composant lui-même en utilisant useContext.

Un composant appelant useContext sera toujours rendu lorsque la valeur de contexte change . Si le rendu du composant est coûteux, vous pouvez l'optimiser en utilisant la mémorisation.

Donc, étant donné l'exemple de code ci-dessous, les composants Number et Text seront rendus à chaque changement de valeur de contexte, car les deux contiennent directement useContext(AppContext).

const AppContext = React.createContext();

const Number = React.memo(props => {
  const renderCount = useRenderCount();
  const contextNo = React.useContext(AppContext);
  return (
    <div style={{ backgroundColor: `${randomColor()}` }}>
      Number: rendered {renderCount.current} times.
    </div>
  );
});

const Text = React.memo(() => {
  const renderCount = useRenderCount();
  const context = React.useContext(AppContext);
  return (
    <div style={{ backgroundColor: `${randomColor()}` }}>
      Text: rendered {renderCount.current} times. I rerender with context value
      changes!
    </div>
  );
});

const App = () => {
  const [ctxVal, setCtxVal] = React.useState(0);
  const [prop, setProp] = React.useState(0);
  return (
    <AppContext.Provider value={ctxVal}>
      <Number prop={prop} />
      <Text />
      <button onClick={() => setCtxVal(ctxVal + 1)}>
        Change context value
      </button>
      <button onClick={() => setProp(prop + 1)}>
        Only change prop in Number
      </button>
    </AppContext.Provider>
  );
};

function useRenderCount() {
  const renderCount = React.useRef(1);
  React.useEffect(() => {
    renderCount.current += 1;
  }); 
  return renderCount;
}

function randomColor() {
  const letters = "0123456789ABCDEF"; let color = "#";
  for (let i = 0; i < 6; i++) color += letters[Math.floor(Math.random() * 16)];
  return color;
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
0
ford04