开发者问题收集

React 上下文(this.context)在构造函数调用时未定义

2021-04-20
1297

我正在尝试编写一个类组件,该组件使用 this.context 中的值来派生状态对象。我有一个方法 getStyle 可以返回这样的对象。在 constructor 时,我调用 this.getStyle 以从已经是最新的状态开始,并加快初始渲染速度。

但是,似乎在 constructor 调用时, this.contextundefined ,并且它一直保持这种状态直到 render 调用时。

我的代码中有什么错误吗?

我不记得 React 的(新)上下文 API 文档中有任何与此类问题相关的详细信息。 this.contextcomponentDidMount 时可用,但是,这需要 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个回答

尝试将上下文传递给构造函数:

constructor(props, context) {
    // your code here
}

根据 这个 ,此解决方案可能已被弃用,但您可以尝试。

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