Utilizzo dell'API React Context
Pubblicato: 2022-03-11L'API React Context è in circolazione da un po' di tempo come funzionalità sperimentale, ma solo nella versione 16.3.0 di React è diventata sicura da usare in produzione. L'articolo seguente ti mostrerà due app di base del negozio web, una creata con l'API Context e una senza di essa.
Questa nuova API risolve un problema importante: la perforazione dell'elica . Anche se non hai familiarità con il termine, se hai lavorato su un'app React.js, probabilmente è successo a te. La perforazione dell'elica è l'elaborazione per ottenere i dati dal componente A al componente Z facendoli passare attraverso più livelli di componenti React intermedi. Il componente riceverà oggetti di scena indirettamente e tu , lo sviluppatore React, dovrai assicurarti che tutto funzioni correttamente.
Esploriamo come gestiresti i problemi comuni senza 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> ); } }
Elenco prodotti .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;
Cars.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> );
Car.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> );
Certo, questo non è il modo migliore per gestire i tuoi dati, ma spero che dimostri perché la perforazione dell'elica fa schifo . Quindi, in che modo l'API Context può aiutarci a evitarlo?
Presentazione di Context Web Store
Eseguiamo il refactoring dell'app e dimostriamo cosa può fare. In poche parole, l'API Context ti consente di avere un archivio centrale in cui risiedono i tuoi dati (sì, proprio come in Redux). Il negozio può essere inserito direttamente in qualsiasi componente. Puoi eliminare l'intermediario!
Il refactoring è abbastanza semplice: non dobbiamo apportare modifiche alla struttura dei componenti. Tuttavia, abbiamo bisogno di creare alcuni nuovi componenti: un fornitore e un consumatore.
1. Inizializzare il contesto
In primo luogo, dobbiamo creare il contesto, che possiamo utilizzare in seguito per creare fornitori e consumatori.

MyContext.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. Crea il provider
Una volta fatto, possiamo importare il contesto e usarlo per creare il nostro provider, che chiameremo MyProvider. In esso, inizializziamo uno stato con alcuni valori, che puoi condividere tramite il nostro componente provider di valore . Nel nostro esempio, condividiamo this.state.cars
insieme a un paio di metodi che manipolano lo stato. Pensa a questi metodi come riduttori in Redux.
MyProvider.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> ); } }
Per rendere il provider accessibile ad altri componenti, dobbiamo avvolgere la nostra app con esso (sì, proprio come in Redux). Già che ci siamo, possiamo sbarazzarci dello stato e dei metodi perché ora sono definiti in 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. Crea il consumatore
Avremo bisogno di importare nuovamente il contesto e avvolgere il nostro componente con esso che inserisce l'argomento del contesto nel componente. Dopo, è piuttosto semplice. Usi il contesto , nello stesso modo in cui useresti gli oggetti di scena. Contiene tutti i valori che abbiamo condiviso in MyProducer, dobbiamo solo usarlo!
Cars.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> );
Cosa abbiamo dimenticato? L'elenco dei prodotti! È qui che il vantaggio diventa evidente. Non trasmettiamo dati o metodi. Il componente è semplificato perché ha bisogno di renderizzare solo alcuni componenti.
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> );
Nel corso di questo articolo, ho fatto alcuni confronti tra Redux e l'API Context. Uno dei maggiori vantaggi di Redux è che la tua app può avere un archivio centrale a cui è possibile accedere da qualsiasi componente. Con la nuova API Context, hai quella funzionalità per impostazione predefinita. È stato fatto molto clamore sul fatto che l'API Context renderà Redux obsoleto.
Questo potrebbe essere vero per quelli di voi che usano Redux solo per le sue capacità di archivio centrale. Se questa è l'unica funzionalità per la quale lo stavi utilizzando, ora puoi sostituirlo con l'API Context ed evitare il drilling prop senza utilizzare librerie di terze parti.
Se sei interessato a misurare e ottimizzare le prestazioni della tua applicazione React, leggi A Guide to Optimizing React Performance del collega Toptaler William Wang.