Travailler avec l'API React Context
Publié: 2022-03-11L'API React Context existe depuis un certain temps en tant que fonctionnalité expérimentale, mais ce n'est que dans la version 16.3.0 de React qu'elle est devenue sûre à utiliser en production. L'article ci-dessous vous montrera deux applications de boutique en ligne de base, l'une construite avec l'API Context et l'autre sans elle.
Cette nouvelle API résout un problème majeur : le forage d'hélices . Même si vous n'êtes pas familier avec le terme, si vous avez travaillé sur une application React.js, cela vous est probablement arrivé. Le forage d'accessoires consiste à obtenir des données du composant A au composant Z en les faisant passer à travers plusieurs couches de composants React intermédiaires. Le composant recevra des accessoires indirectement et vous , le développeur React, devrez vous assurer que tout fonctionne correctement.
Explorons comment vous géreriez les problèmes courants sans l'API React Context,
App.js
class App extends Component { state = { cars: { car001: { name: 'Honda', price: 100 }, car002: { name: 'BMW', price: 150 }, car003: { name: 'Mercedes', price: 200 } } }; incrementCarPrice = this.incrementCarPrice.bind(this); decrementCarPrice = this.decrementCarPrice.bind(this); incrementCarPrice(selectedID) { // a simple method that manipulates the state const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price + 1; this.setState({ cars }); } decrementCarPrice(selectedID) { // a simple method that manipulates the state const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price - 1; this.setState({ cars }); } render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to my web store</h1> </header> {/* Pass props twice */} <ProductList cars={this.state.cars} incrementCarPrice={this.incrementCarPrice} decrementCarPrice={this.decrementCarPrice} /> </div> ); } }
Liste de produits .js
const ProductList = props => ( <div className="product-list"> <h2>Product list:</h2> {/* Pass props twice */} <Cars cars={props.cars} incrementCarPrice={props.incrementCarPrice} decrementCarPrice={props.decrementCarPrice} /> {/* Other potential product categories which we will skip for this demo: */} {/* <Electronics /> */} {/* <Clothes /> */} {/* <Shoes /> */} </div> ); export default ProductList;
Voitures.js
const Cars = props => ( <Fragment> <h4>Cars:</h4> {/* Finally we can use data */} {Object.keys(props.cars).map(carID => ( <Car key={carID} name={props.cars[carID].name} price={props.cars[carID].price} incrementPrice={() => props.incrementCarPrice(carID)} decrementPrice={() => props.decrementCarPrice(carID)} /> ))} </Fragment> );
Voiture.js
const Cars = props => ( <Fragment> <p>Name: {props.name}</p> <p>Price: ${props.price}</p> <button onClick={props.incrementPrice}>↑</button> <button onClick={props.decrementPrice}>↓</button> </Fragment> );
Certes, ce n'est pas la meilleure façon de gérer vos données, mais j'espère que cela démontre pourquoi le forage d'hélice est nul . Alors, comment l'API Context peut-elle nous aider à éviter cela ?
Présentation de la boutique en ligne de contexte
Refactorisons l'application et démontrons ce qu'elle peut faire. En quelques mots, l'API Context vous permet d'avoir un magasin central où résident vos données (oui, comme dans Redux). Le magasin peut être inséré directement dans n'importe quel composant. Vous pouvez supprimer l'intermédiaire !
La refactorisation est assez simple - nous n'avons pas à apporter de modifications à la structure des composants. Nous devons cependant créer de nouveaux composants - un fournisseur et un consommateur.
1. Initialiser le contexte
Tout d'abord, nous devons créer le contexte, que nous pourrons ensuite utiliser pour créer des fournisseurs et des consommateurs.
MonContexte.js

import React from 'react'; // this is the equivalent to the createStore method of Redux // https://redux.js.org/api/createstore const MyContext = React.createContext(); export default MyContext;
2. Créez le fournisseur
Une fois cela fait, nous pouvons importer le contexte et l'utiliser pour créer notre fournisseur, que nous appelons MyProvider. Dans celui-ci, nous initialisons un état avec certaines valeurs, que vous pouvez partager via value prop notre composant provider. Dans notre exemple, nous partageons this.state.cars
avec quelques méthodes qui manipulent l'état. Considérez ces méthodes comme des réducteurs dans Redux.
MonFournisseur.js
import MyContext from './MyContext'; class MyProvider extends Component { state = { cars: { car001: { name: 'Honda', price: 100 }, car002: { name: 'BMW', price: 150 }, car003: { name: 'Mercedes', price: 200 } } }; render() { return ( <MyContext.Provider value={{ cars: this.state.cars, incrementPrice: selectedID => { const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price + 1; this.setState({ cars }); }, decrementPrice: selectedID => { const cars = Object.assign({}, this.state.cars); cars[selectedID].price = cars[selectedID].price - 1; this.setState({ cars }); } }} > {this.props.children} </MyContext.Provider> ); } }
Pour rendre le fournisseur accessible à d'autres composants, nous devons envelopper notre application avec (oui, comme dans Redux). Tant qu'on y est, on peut se débarrasser de l'état et des méthodes car ils sont désormais définis dans MyProvider.js.
App.js
class App extends Component { render() { return ( <MyProvider> <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <h1 className="App-title">Welcome to my web store</h1> </header> <ProductList /> </div> </MyProvider> ); } }
3. Créez le consommateur
Nous devrons réimporter le contexte et envelopper notre composant avec celui-ci, ce qui injecte l'argument de contexte dans le composant. Après, c'est assez simple. Vous utilisez le contexte , de la même manière que vous utiliseriez les accessoires . Il contient toutes les valeurs que nous avons partagées dans MyProducer, nous avons juste besoin de l'utiliser !
Voitures.js
const Cars = () => ( <MyContext.Consumer> {context => ( <Fragment> <h4>Cars:</h4> {Object.keys(context.cars).map(carID => ( <Car key={carID} name={context.cars[carID].name} price={context.cars[carID].price} incrementPrice={() => context.incrementPrice(carID)} decrementPrice={() => context.decrementPrice(carID)} /> ))} </Fragment> )} </MyContext.Consumer> );
Qu'avons-nous oublié ? La liste de produits ! C'est là que l'avantage devient évident. Nous ne transmettons aucune donnée ou méthode. Le composant est simplifié car il ne nécessite que le rendu de quelques composants.
ProductList.js
const ProductList = () => ( <div className="product-list"> <h2>Product list:</h2> <Cars /> {/* Other potential product categories which we will skip for this demo: */} {/* <Electronics /> */} {/* <Clothes /> */} {/* <Shoes /> */} </div> );
Au cours de cet article, j'ai fait quelques comparaisons entre Redux et l'API Context. L'un des principaux avantages de Redux est le fait que votre application peut disposer d'un magasin central accessible à partir de n'importe quel composant. Avec la nouvelle API Context, vous disposez de cette fonctionnalité par défaut. Beaucoup de battage médiatique a été fait sur le fait que l'API Context rendra Redux obsolète.
Cela peut être vrai pour ceux d'entre vous qui n'utilisent Redux que pour ses capacités de magasin central. Si c'est la seule fonctionnalité pour laquelle vous l'utilisiez, vous pouvez maintenant la remplacer par l'API contextuelle et éviter le forage d'accessoires sans utiliser de bibliothèques tierces.
Si vous souhaitez mesurer et optimiser les performances de votre application React, lisez A Guide to Optimizing React Performance par son collègue Toptaler William Wang.