多个 React 上下文:内部一个依赖于外部一个不起作用
Multiple React Context: inner one depending on outer one doesn't work
我想为我的应用程序使用 2 个 React 上下文。
- 第一个上下文是UserContext,加载用户信息。
- 第二个上下文是 ItemContext,它根据用户 ID 加载项目信息。
为简单起见,我使用同步函数来加载用户和项目信息。有关完整的工作示例,请参阅 CodeSandbox。
// index.js
import React from "react";
import ReactDOM from "react-dom";
import { ItemProvider, ItemConsumer } from "./ItemContext";
import { UserProvider, UserConsumer } from "./UserContext";
class App extends React.Component {
render() {
return (
<UserProvider>
<UserConsumer>
{({ user }) => (
<ItemProvider user={user}>
<ItemConsumer>
{({ item }) => <div>{JSON.stringify(item, null, 2)}</div>}
</ItemConsumer>
</ItemProvider>
)}
</UserConsumer>
</UserProvider>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
// UserContext.js
import React from "react";
const { Provider, Consumer } = React.createContext();
class UserProvider extends React.Component {
state = {
isLoading: false,
value: { user: {} }
};
async componentDidMount() {
this.setState({ isLoading: true });
const user = { id: 1, name: "evan" };
this.setState({ value: { user }, isLoading: false });
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { UserProvider, Consumer as UserConsumer };
// ItemContext.js
import React from "react";
const { Provider, Consumer } = React.createContext();
const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };
const getItemByUserId = userId => items[userId];
class ItemProvider extends React.Component {
state = {
isLoading: false,
value: { item: {} }
};
async componentDidMount() {
this.setState({ isLoading: true });
const item = getItemByUserId(1);
// console.log(this.props.user); // Object {}
// const item = getItemByUserId(this.props.user.id);
this.setState({ value: { item }, isLoading: false });
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { ItemProvider, Consumer as ItemConsumer };
我无法在 ItemContext
中执行 const item = getItemByUserId(this.props.user.id);
因为 this.props.user
是一个空对象。
解决方法是什么?
用户值从 UserContext 中异步呈现,并且在子项呈现之前不可用,因此您需要在 ItemProvider
中实现 componentDidUpdate 以根据用户属性获取上下文值
import React from "react";
const { Provider, Consumer } = React.createContext();
const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };
const getItemByUserId = userId => items[userId];
class ItemProvider extends React.Component {
state = {
isLoading: false,
value: { item: {} }
};
async componentDidMount() {
if (this.props.user && this.props.user.id) {
this.setState({ isLoading: true });
const item = getItemByUserId(this.props.user.id);
this.setState({ value: { item }, isLoading: true });
}
}
componentDidUpdate(prevProps) {
console.log(this.props.user, prevProps.user);
if (prevProps.user !== this.props.user) {
const item = getItemByUserId(this.props.user.id);
this.setState({
value: { item }
});
}
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
console.log(value);
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { ItemProvider, Consumer as ItemConsumer };
我想为我的应用程序使用 2 个 React 上下文。
- 第一个上下文是UserContext,加载用户信息。
- 第二个上下文是 ItemContext,它根据用户 ID 加载项目信息。
为简单起见,我使用同步函数来加载用户和项目信息。有关完整的工作示例,请参阅 CodeSandbox。
// index.js
import React from "react";
import ReactDOM from "react-dom";
import { ItemProvider, ItemConsumer } from "./ItemContext";
import { UserProvider, UserConsumer } from "./UserContext";
class App extends React.Component {
render() {
return (
<UserProvider>
<UserConsumer>
{({ user }) => (
<ItemProvider user={user}>
<ItemConsumer>
{({ item }) => <div>{JSON.stringify(item, null, 2)}</div>}
</ItemConsumer>
</ItemProvider>
)}
</UserConsumer>
</UserProvider>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
// UserContext.js
import React from "react";
const { Provider, Consumer } = React.createContext();
class UserProvider extends React.Component {
state = {
isLoading: false,
value: { user: {} }
};
async componentDidMount() {
this.setState({ isLoading: true });
const user = { id: 1, name: "evan" };
this.setState({ value: { user }, isLoading: false });
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { UserProvider, Consumer as UserConsumer };
// ItemContext.js
import React from "react";
const { Provider, Consumer } = React.createContext();
const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };
const getItemByUserId = userId => items[userId];
class ItemProvider extends React.Component {
state = {
isLoading: false,
value: { item: {} }
};
async componentDidMount() {
this.setState({ isLoading: true });
const item = getItemByUserId(1);
// console.log(this.props.user); // Object {}
// const item = getItemByUserId(this.props.user.id);
this.setState({ value: { item }, isLoading: false });
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { ItemProvider, Consumer as ItemConsumer };
我无法在 ItemContext
中执行 const item = getItemByUserId(this.props.user.id);
因为 this.props.user
是一个空对象。
解决方法是什么?
用户值从 UserContext 中异步呈现,并且在子项呈现之前不可用,因此您需要在 ItemProvider
中实现 componentDidUpdate 以根据用户属性获取上下文值
import React from "react";
const { Provider, Consumer } = React.createContext();
const items = { 1: { name: "a red hat" }, 2: { name: "a blue shirt" } };
const getItemByUserId = userId => items[userId];
class ItemProvider extends React.Component {
state = {
isLoading: false,
value: { item: {} }
};
async componentDidMount() {
if (this.props.user && this.props.user.id) {
this.setState({ isLoading: true });
const item = getItemByUserId(this.props.user.id);
this.setState({ value: { item }, isLoading: true });
}
}
componentDidUpdate(prevProps) {
console.log(this.props.user, prevProps.user);
if (prevProps.user !== this.props.user) {
const item = getItemByUserId(this.props.user.id);
this.setState({
value: { item }
});
}
}
render() {
const { isLoading, value } = this.state;
if (isLoading) {
return <div>Loading data...</div>;
}
console.log(value);
return <Provider value={value}>{this.props.children}</Provider>;
}
}
export { ItemProvider, Consumer as ItemConsumer };