En mi proyecto React, quería compartir la moneda, que seleccionó el usuario, dentro de los componentes usando un contexto. La funcionalidad de contexto funciona bien, sin embargo, hay un pequeño problema que quiero solucionar. Está configurando la moneda predeterminada para el contexto. Entonces, cuando la web se inicia desde el principio, habrá una moneda predeterminada establecida en el contexto, que provendrá de la selección que se proporciona desde el punto final. Utilicé una declaración if como se muestra en CurrencySelector.js, pero recibí el error "Profundidad máxima de actualización excedida". Proporcioné mi código para el componente de selección de contexto y moneda.
import React, { Component, createContext } from "react"; const CurrencyContext = createContext(); class CurrencyContextProvider extends Component { state = { selectedCurrency: "uuu" }; setCurrency = (c) => { this.setState({ selectedCurrency: c }); }; render() { return ( <CurrencyContext.Provider value={{ ...this.state, setCurrency: this.setCurrency }} > {this.props.children} </CurrencyContext.Provider> ); } } class CurrencySelector extends React.Component { constructor(props) { super(props); console.log("CurrencySelector constructor"); this.state = { currencies: [] }; } async componentDidMount() { let currencies = (await this.getCurrencies()).data .currencies; this.setState({ currencies: currencies }); } async getCurrencies() { return await fetchAnyQuery(`query{ currencies }`); } render() { return ( <CurrencyContext.Consumer> {(currencyContext) => { const { selectedCurrency, setCurrency, } = currencyContext; return ( <select name="currency-selector" onChange={(event) => { setCurrency(event.target.value); }} > {this.state.currencies.map((currency, index) => { //When I wrote this if-statement I got the error if (index == 0) { setCurrency(currency); } return ( <option value={currency}>{currency}</option> ); })} </select> ); }} </CurrencyContext.Consumer> ); } }//When I wrote this if-statement I got the error if (index == 0) { setCurrency(currency); }Sí, obtendrá un error, ya que está mutando el estado durante el renderizado , lo cual está expresamente prohibido. (Esto no es específico del uso de un contexto).
Tienes un par de opciones que se me ocurren:
He aquí un ejemplo de la primera opción.
Vea cómo se ha getCurrencies() al componentDidMount() del proveedor.
Será necesario tener un poco de cuidado adicional, ya que es posible que las monedas aún no se hayan cargado; vea cómo solo renderizamos "Cargando..." para ese momento.
import React, { Component, createContext } from "react"; const CurrencyContext = createContext(); // Fake fetcher function that just takes a bit of time. function fetchAnyQuery() { return new Promise((resolve) => setTimeout(() => resolve({ data: { currencies: ["a", "b", "c"] } }), 1000) ); } class CurrencyContextProvider extends Component { state = { selectedCurrency: "uuu", currencies: undefined }; setCurrency = (c) => { this.setState({ selectedCurrency: c }); }; async componentDidMount() { const currencies = (await this.getCurrencies()).data.currencies; this.setState(({ selectedCurrency }) => { if (!currencies.includes(selectedCurrency)) { // If the selected currency is invalid, reset it to the first one selectedCurrency = currencies[0]; } return { currencies, selectedCurrency }; }); } async getCurrencies() { return await fetchAnyQuery(`query{ currencies }`); } render() { return ( <CurrencyContext.Provider value={{ ...this.state, setCurrency: this.setCurrency }} > {this.state.currencies ? this.props.children : <>Loading...</>} </CurrencyContext.Provider> ); } } class CurrencySelector extends React.Component { render() { return ( <CurrencyContext.Consumer> {(currencyContext) => { const { selectedCurrency, currencies, setCurrency } = currencyContext; return ( <div> <select name="currency-selector" value={selectedCurrency} onChange={(event) => { setCurrency(event.target.value); }} > {currencies.map((currency) => ( <option value={currency} key={currency}> {currency} </option> ))} </select> <br /> Selected: {selectedCurrency} </div> ); }} </CurrencyContext.Consumer> ); } } export default function App() { return ( <CurrencyContextProvider> <CurrencySelector /> </CurrencyContextProvider> ); }