【问题标题】:How to get context from higher order component in constructor of child component?如何在子组件的构造函数中从高阶组件获取上下文?
【发布时间】:2021-04-19 22:20:38
【问题描述】:

我有以下上下文提供程序,可让我访问整个应用程序的上下文:

import React, { Component, useContext } from 'react';
import { appInitialization, Context } from "@microsoft/teams-js";
import TeamsContextService from '../Services/TeamsContextService';
import Constants from '../Constants/AppConstants';

const TeamsContext = React.createContext({});

interface Error {
    status: boolean,
    message: appInitialization.IFailedRequest
}

interface TeamsContextProviderState {
    teamsContext : any,
    error?: Error
}

class TeamsContextProvider extends Component<{}, TeamsContextProviderState> {
    getContext: Function
    state: TeamsContextProviderState = {
        teamsContext: {},
        error: undefined
    }

    constructor(props: any) {
        super(props);
        this.getContext = TeamsContextService();
    }

    componentDidMount() {
        this.getContext()
            .then((context: Context) => {
                const frameContext = context.frameContext || "";
                if (frameContext === Constants.Surfaces.SidePanel) {
                    this.setState({
                        teamsContext: context,
                    })
                    appInitialization.notifySuccess();
                    return;
                }
                return Promise.reject("Error: Please make sure to run the app within teams as a tab app");
            })
            .catch((msg: appInitialization.IFailedRequest) => {
                appInitialization.notifyFailure(msg);
                this.setState({
                    error: {
                        status: true,
                        message: msg,
                    }
                })
            });
    }

    render() {
        return (
            <TeamsContext.Provider value={this.state.teamsContext}>
                {this.props.children}
            </TeamsContext.Provider>
        );
    }
}

export default TeamsContextProvider;

export const withTeamsContext = (Component: any) => (props: any) => {
    const teamsContext = useContext(TeamsContext);
    return <Component {...props} teamsContext={teamsContext} />
}

这是由主应用程序使用的:

class App extends Component {
    render() {
      return (
        <Fragment>
            <TeamsContextProvider>
                <SurfaceSelector/>
            </TeamsContextProvider>
        </Fragment>
      );
    }
}

export default App;

SurfaceSelector 子组件中,我想访问 TeamsContextProvider teamsContext 属性。然而,在SurfaceSelector 的构造函数中,它为其子属性返回undefined。但是一旦它到达表面选择器的render 功能,那么teamsContext 就会正确填充。我想使用teamsContext 上的theme 属性来更新当前选择的主题,但我不能在构造函数中这样做,因为它是未定义的,并且在渲染中我将无法设置状态没有导致无限循环。有什么办法解决这个问题?我尝试了componentDidUpdatecomponentWillUpdate 和其他反应生命周期方法,但如果我尝试更新状态,它们都会以无限循环告终。我尝试了useContext,但我不能在SurfaceSelector 组件中这样做,因为它是一个类组件,需要状态来管理主题。

这里是SurfaceSelector

import { Component, Fragment } from 'react';
import SidePanelPage from '../Pages/SidePanel';
import { withTeamsContext } from '../Contexts/TeamsContextProvider';
import Constants from '../Constants/AppConstants';
import { Context, registerOnThemeChangeHandler } from '@microsoft/teams-js';
import { Provider, teamsDarkV2Theme, teamsHighContrastTheme, ThemeInput} from '@fluentui/react-northstar'
import { i18n } from '@lingui/core'
import { I18nProvider } from '@lingui/react'
import { defaultLocale, dynamicActivate } from '../i18n'

export interface SurfaceSelectorProps {
    teamsContext: Context
}

interface SurfaceSelectorState {
    theme?: ThemeInput<any>
}

class SurfaceSelector extends Component<SurfaceSelectorProps, SurfaceSelectorState> {
    constructor(props: SurfaceSelectorProps) {
        super(props)
        this.state = {
            theme: this.getTheme(this.props.teamsContext.theme)
        }
    }

    private getTheme(theme?: string) {
        switch (theme) {
            case "dark":
                return teamsDarkV2Theme;
            case "contrast":
                return teamsHighContrastTheme;
        }
        return teamsDarkV2Theme;
    }

    render() {
        const { SidePanel } = Constants.Surfaces;
        const frameContext = this.props.teamsContext.frameContext;
        switch (frameContext) {
            case SidePanel:
                return (
                    <Fragment>
                        <I18nProvider i18n={i18n}>
                            <Provider theme={this.state.theme}>
                                <SidePanelPage />
                            </Provider>
                        </I18nProvider>
                    </Fragment>
                )
            default:
                return null;
        }
    }
}

export default withTeamsContext(SurfaceSelector);

【问题讨论】:

    标签: reactjs typescript react-hooks


    【解决方案1】:

    我已经重写了你的代码以了解你在做什么,因为我完成了它只是工作。

    它比你的干净多了,所以更容易找出你缺少的东西。

    看看here

    【讨论】:

    • 嗯,看看链接中的控制台,它说团队上下文仍然是一个空对象。里面不应该有 foo 的值吗?
    • 是的,这与道具在渲染中可用但在 SurfaceSelector 的构造函数中不可用的问题相同。我在渲染中看到 {teamscontext: { foo: 1}} 但在构造函数中看不到:(
    • 你只需要在context的构造函数中设置对象,改变沙箱
    • 因此,如果我们查看 Context 中的 ComponentDidUpdate 并将 setState 更改为 0,那么 SurfaceSelector 的构造函数中的值不会显示为 0,它仍然只显示 1。由于我正在执行工作componentDidUpdate 我需要将更改反映到 SurfaceSelector 的构造函数中。
    猜你喜欢
    • 2020-06-05
    • 2013-01-12
    • 2019-01-26
    • 1970-01-01
    • 2019-12-15
    • 2019-06-14
    • 2020-02-01
    • 2017-09-10
    • 1970-01-01
    相关资源
    最近更新 更多