Lucrul cu API-ul React Context
Publicat: 2022-03-11API-ul React Context există de ceva vreme ca o caracteristică experimentală, dar numai în versiunea React 16.3.0 a devenit sigur de utilizat în producție. Articolul de mai jos vă va arăta două aplicații de bază pentru magazinul web, una construită cu API-ul Context și alta fără acesta.
Acest nou API rezolvă o problemă majoră – găurirea suportului . Chiar dacă nu ești familiarizat cu termenul, dacă ai lucrat la o aplicație React.js, probabil ți s-a întâmplat. Forajul cu prop este procesarea obținerii datelor de la componenta A la componenta Z prin trecerea lor prin mai multe straturi de componente React intermediare. Componenta va primi elemente de recuzită indirect, iar dvs. , dezvoltatorul React, va trebui să vă asigurați că totul funcționează corect.
Să explorăm cum ați gestiona problemele comune fără API-ul 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> ); } }
ProductList .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> );
Desigur, acesta nu este cel mai bun mod de a vă gestiona datele, dar sper că acesta demonstrează de ce forarea cu prop este nasolă . Deci, cum ne poate ajuta Context API-ul să evităm acest lucru?
Vă prezentăm Magazinul Web Context
Să refactorăm aplicația și să demonstrăm ce poate face. În câteva cuvinte, API-ul Context îți permite să ai un magazin central unde se află datele tale (da, la fel ca în Redux). Magazinul poate fi introdus direct în orice componentă. Îl poți tăia pe intermediar!
Refactorizarea este destul de ușoară – nu trebuie să facem nicio modificare asupra modului în care sunt structurate componentele. Totuși, trebuie să creăm câteva componente noi – un furnizor și un consumator.
1. Inițializați contextul
În primul rând, trebuie să creăm contextul, pe care să îl putem folosi ulterior pentru a crea furnizori și 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ți furnizorul
Odată ce s-a terminat, putem importa contextul și îl putem folosi pentru a crea furnizorul nostru, pe care îl numim MyProvider. În ea, inițializam o stare cu niște valori, pe care le puteți partaja prin intermediul componentei furnizorului nostru de valoare . În exemplul nostru, this.state.cars
împreună cu câteva metode care manipulează starea. Gândiți-vă la aceste metode ca la reduceri în 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> ); } }
Pentru a face furnizorul accesibil altor componente, trebuie să ne împachetăm aplicația cu el (da, la fel ca în Redux). În timp ce suntem la asta, putem scăpa de stare și metode, deoarece acestea sunt acum definite în 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ți Consumatorul
Va trebui să importam din nou contextul și să împachetăm componenta noastră cu el, care injectează argumentul context în componentă. După aceea, este destul de simplu. Folosești contextul , în același mod în care ai folosi recuzita . Deține toate valorile pe care le-am împărtășit în MyProducer, trebuie doar să-l folosim!
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> );
Ce am uitat? Lista de produse! Aici devine evident beneficiul. Nu transmitem date sau metode. Componenta este simplificată pentru că trebuie doar să redea câteva componente.
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> );
Pe parcursul acestui articol, am făcut câteva comparații între Redux și API-ul Context. Unul dintre cele mai mari avantaje ale Redux este faptul că aplicația dvs. poate avea un magazin central care poate fi accesat din orice componentă. Cu noul Context API, aveți această funcționalitate în mod implicit. S-a făcut o mulțime de hype că API-ul Context va face Redux învechit.
Acest lucru ar putea fi adevărat pentru cei dintre voi care folosesc Redux doar pentru capacitățile sale de magazin central. Dacă aceasta este singura caracteristică pentru care o utilizați, o puteți înlocui acum cu API-ul Context și să evitați perforarea prop fără a utiliza biblioteci terțe.
Dacă sunteți interesat să măsurați și să optimizați performanța aplicației dvs. React, citiți Un ghid pentru optimizarea performanței React de către coleg Toptaler William Wang.