javascript - 为什么在将数据设置为上下文时出现超出最大更新深度的错误(React)
问题描述
在我的 React 项目中,我想使用上下文在组件中共享用户选择的货币。上下文功能工作正常,但是,我想解决一个小问题。它将默认货币设置为上下文。因此,当网络从一开始就启动时,将为上下文设置一个默认货币,这将来自端点提供的选择。我使用了 CurrencySelector.js 中所示的 if 语句,但我收到了“超过最大更新深度”错误。我为上下文和货币选择组件提供了我的代码。
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);
}
是的——你会得到一个错误,因为你在 render 期间改变了状态,这是明确禁止的。(这并不特定于使用上下文。)
你有几个我能想到的选择:
- 将货币加载移动到上下文提供程序,并让上下文提供程序在加载货币后设置默认货币
- 如果尚未设置默认货币,则“假”设置为默认货币(但这会很快变得毛茸茸)
这是第一个选项的示例。
查看如何getCurrencies()
被提升到componentDidMount()
提供者的位置。
需要格外小心,因为可能还没有加载货币;看看我们如何只在那个时候渲染“Loading...”。
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>
);
}
推荐阅读
- ansible - Vagrant box 没有在 WSL2 下设置运行
- java - 覆盖 Spring 启动健康端点
- pddl - 创建 PDDL 域和问题 - Game Kami
- laravel - 如何在 Laravel 上使用扩展重定向路由?
- powershell - Powershell 5.1 - 找不到类型 [MyType]:验证是否加载了包含此类型的程序集
- mysql - 使用 pgloader 从 Mysql 8 迁移到 postgres 失败
- sql - 避免多次调用 T-SQL 函数
- php - 使用 PHP 重新加载包含新 div 内容的页面
- java - 从字符串JAVA中提取复数
- java - 有没有办法在 JFreeChart 中将十字准线标签调整几个像素?