React 上下文(this.context)在构造函数调用时未定义
2021-04-20
1297
我正在尝试编写一个类组件,该组件使用
this.context
中的值来派生状态对象。我有一个方法
getStyle
可以返回这样的对象。在
constructor
时,我调用
this.getStyle
以从已经是最新的状态开始,并加快初始渲染速度。
但是,似乎在
constructor
调用时,
this.context
是
undefined
,并且它一直保持这种状态直到
render
调用时。
我的代码中有什么错误吗?
我不记得 React 的(新)上下文 API 文档中有任何与此类问题相关的详细信息。
this.context
在
componentDidMount
时可用,但是,这需要
setState
,这将导致额外的组件重新渲染,而这正是我想要避免的。
下面是我正在尝试使用的代码:
import React from "react";
import { View, Text } from "react-native";
const defaultTheme = {
light: { backgroundColor: "white" },
dark: { backgroundColor: "black" }
};
const customTheme = {
light: { backgroundColor: "#EEE" },
dark: { backgroundColor: "#111" },
};
const MyContext = React.createContext(defaultTheme);
class Container extends React.PureComponent {
static contextType = MyContext;
constructor(props) {
super(props);
this.state = this.getStyle(); // TypeError: undefined is not an object (evaluating '_this.context[_this.props.colorScheme || "light"]')
// this.state = {}; // use this to try the componentDidMount alternative
}
componentDidMount = () => {
const style = this.getStyle();
this.setState(style);
}
getStyle = () => {
// this.props.colorScheme = "light" | "dark" | null | undefined
return this.context[this.props.colorScheme || "light"];
}
componentDidUpdate = (prevProps, prevState, snapshot) => {
if (prevProps.colorScheme !== this.props.colorScheme) {
const style = this.getStyle();
this.setState(style);
}
}
render = () => {
return <View style={this.state}>
{this.props.children}
</View>;
}
}
export default function App() {
return <MyContext.Provider value={customTheme}>
<Container>
<Text>Hello, world!</Text>
</Container>
</MyContext.Provider>
}
3个回答
Huu Tho Tran Nguyen
2021-11-11
对于使用 React 18+ 偶然发现此问题的人来说,我能让它工作的唯一方法是访问类组件中
render()
方法内的
this.conext
。
James Crain
2022-11-23
除了上面发布的解决方案之外,还有另一种解决方案:上下文包装器组件,将上下文作为 props 传递。
您创建一个 Wrapper 组件,该组件在其渲染函数中使用上下文值,并在构造函数时将其传递给需要这些 props 的组件:
class TheActualComponent extends React.PureComponent {
constructor(props) {
super(props);
console.log(props.context); // Now you've got'em
}
// ...
}
// SFC wrapper
function WrapperComponent(props) {
const contextProps = React.useContext(MyContext);
return <TheActualComponent {...props} context={contextProps}>
{props.children}
</TheActualComponent>;
}
// class component wrapper
class WrapperClassComponent extends React.PureComponent {
static contextType = MyContext;
render() {
return <TheActualComponent {...this.props} context={this.context}>
{this.props.children}
</TheActualComponent>;
}
}
cristian
2022-11-25