Trabalhando com a API React Context
Publicados: 2022-03-11A API do React Context já existe como um recurso experimental há algum tempo, mas apenas na versão 16.3.0 do React ela se tornou segura para uso em produção. O artigo abaixo mostrará dois aplicativos básicos de loja da web, um criado com a API de contexto e outro sem ela.
Esta nova API resolve um grande problema – perfuração de suporte . Mesmo que você não esteja familiarizado com o termo, se já trabalhou em um aplicativo React.js, provavelmente já aconteceu com você. O Prop drill é o processamento de obter dados do componente A para o componente Z, passando-os por várias camadas de componentes intermediários do React. O componente receberá props indiretamente e você , o React Developer, terá que garantir que tudo dê certo.
Vamos explorar como você lidaria com problemas comuns sem a 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> ); } }
Lista de produtos .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;
Carros.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> );
Concedido, esta não é a melhor maneira de lidar com seus dados, mas espero que demonstre por que a perfuração de prop é uma droga . Então, como a Context API pode nos ajudar a evitar isso?
Apresentando a Context Web Store
Vamos refatorar o aplicativo e demonstrar o que ele pode fazer. Em poucas palavras, a Context API permite que você tenha um armazenamento central onde seus dados residem (sim, assim como no Redux). A loja pode ser inserida em qualquer componente diretamente. Você pode cortar o intermediário!
A refatoração é bastante fácil – não precisamos fazer nenhuma alteração na forma como os componentes são estruturados. No entanto, precisamos criar alguns novos componentes – um provedor e um consumidor.
1. Inicialize o contexto
Primeiro, precisamos criar o contexto, que podemos usar posteriormente para criar provedores e consumidores.

MeuContexto.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. Crie o provedor
Feito isso, podemos importar o contexto e usá-lo para criar nosso provedor, que estamos chamando de MyProvider. Nele, inicializamos um estado com alguns valores, que você pode compartilhar via value prop do nosso componente provedor. Em nosso exemplo, estamos compartilhando this.state.cars
junto com alguns métodos que manipulam o estado. Pense nesses métodos como redutores no Redux.
MeuProvedor.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> ); } }
Para tornar o provedor acessível a outros componentes, precisamos envolver nosso aplicativo com ele (sim, assim como no Redux). Enquanto estamos nisso, podemos nos livrar do estado e dos métodos porque eles agora estão definidos em 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. Crie o Consumidor
Precisaremos importar o contexto novamente e envolver nosso componente com ele, o que injeta o argumento context no componente. Depois, é bem direto. Você usa context , da mesma forma que usaria props . Ele contém todos os valores que compartilhamos no MyProducer, só precisamos usá-lo!
Carros.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> );
O que nós esquecemos? A Lista de Produtos! É aí que o benefício se torna aparente. Não passamos nenhum dado ou método. O componente é simplificado porque só precisa renderizar alguns componentes.
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> );
Ao longo deste artigo, fiz algumas comparações entre o Redux e a Context API. Uma das maiores vantagens do Redux é o fato de que seu aplicativo pode ter uma loja central que pode ser acessada de qualquer componente. Com a nova Context API, você tem essa funcionalidade por padrão. Muito hype foi feito de que a Context API tornará o Redux obsoleto.
Isso pode ser verdade para aqueles que usam apenas o Redux para seus recursos de armazenamento central. Se esse é o único recurso para o qual você estava usando, agora você pode substituí-lo pela API de contexto e evitar a perfuração de prop sem usar bibliotecas de terceiros.
Se você estiver interessado em medir e otimizar o desempenho do seu aplicativo React, leia A Guide to Optimizing React Performance do colega Toptaler William Wang.