React给Context赋值触发Maximum Update Depth Exceeded错误如何解决
错误原因
你在render渲染方法的map遍历中直接调用了修改Context状态的setCurrency方法,触发了无限更新循环:
- 调用
setCurrency会更新CurrencyContext的全局状态 - Context状态变更会触发所有消费该Context的组件重新渲染,你的
CurrencySelector组件也会重新执行render方法 - 重新执行
render时又会走到遍历货币列表的逻辑,再次调用setCurrency,循环往复直到超出React的最大更新深度限制,触发报错。
补充:React的渲染函数必须是纯函数,不能包含修改状态这类副作用操作
修复方案
将设置默认货币的逻辑从渲染阶段移到接口请求完成的生命周期中执行:
- 给
CurrencySelector类添加contextType配置,方便在生命周期方法中直接访问Context - 在
componentDidMount拿到接口返回的货币列表后,再执行默认货币的设置逻辑 - 删除
render方法map遍历中调用setCurrency的判断代码
修改后完整代码
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 { // 新增:配置contextType,用于在生命周期中访问Context static contextType = CurrencyContext; constructor(props) { super(props); console.log("CurrencySelector constructor"); this.state = { currencies: [] }; } async componentDidMount() { let currencies = (await this.getCurrencies()).data.currencies; this.setState({ currencies: currencies }); // 新增:在这里设置默认货币 if (currencies.length > 0) { const { setCurrency, selectedCurrency } = this.context; // 加判断避免不必要的重复更新 if (selectedCurrency !== currencies[0]) { setCurrency(currencies[0]); } } } async getCurrencies() { return await fetchAnyQuery(`query{ currencies }`); } render() { return ( <CurrencyContext.Consumer> {(currencyContext) => { const { selectedCurrency, setCurrency, } = currencyContext; return ( <select name="currency-selector" value={selectedCurrency} onChange={(event) => { setCurrency(event.target.value); }} > {this.state.currencies.map((currency, index) => { // 删除了原来在这里的setCurrency调用逻辑 return ( <option value={currency} key={currency}>{currency}</option> ); })} </select> ); }} </CurrencyContext.Consumer> ); } }
补充:还额外给select加了value绑定和option加了key属性,都是React列表渲染和表单组件的最佳实践
内容的提问来源于stack exchange,提问作者asem shaat
相关产品推荐
相关产品推荐

