v16.6.0或更高版本在提供上下文的组件中使用子级时,Context API无法正常工作

ysf*_*ran 5 typescript reactjs tsx react-context

我通过声明public static contextType消耗上下文的组件内部来使用react的新上下文API(v16.6.0或更高版本).只要声明Provider它的组件不直接使用消耗其render()方法中的上下文的组件,这就可以正常工作.

例:

ParentWithContext

这是创建和提供上下文的组件.

export const SomeContext = React.createContext({
  someValue: false
});

export default class ParentWithContext extends Component {
  public render(){
    const contextValue = {someValue: true};
    return (
      <SomeContext.Provider value={contextValue}>
        <ChildOne />
        {this.props.children}
      </SomeContext.Provider>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此组件ChildOne在其render()方法中使用组件(右下方).

ChildOneChildTwo

这两个组件只是消耗上面的上下文并显示它.

export default class ChildOne extends Component {
  public static contextType = SomeContext;
  public render(){
    return (
      <div>
        {`Context of ChildOne: ${this.context.someValue}`}
      </div>
    );
  }
}

export default class ChildTwo extends Component {
  public static contextType = SomeContext;
  public render(){
    return (
      <div>
        {`Context of ChildTwo: ${this.context.someValue}`}
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

index.tsx

class App extends Component {

  render() {
    return (
      <ParentWithContext>
        <ChildTwo />
        <ChildOne />
      </ParentWithContext>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

运行此示例将生成以下行:

Context of ChildOne: undefined
Context of ChildTwo: true
Context of ChildOne: undefined
Run Code Online (Sandbox Code Playgroud)

所以ChildTwo似乎从中收到了正确的信息this.context,而ChildOne没有收到任何信息.

现在来了一个奇怪的部分(对我而言):当你<ChildOne/>从中移除ParentWithContext它时突然适用于两者ChildOneChildTwo

新的ParentWithContext

export default class ParentWithContext extends Component {
  public render(){
    const contextValue = {someValue: true};
    return (
      <SomeContext.Provider value={contextValue}>
        {this.props.children}
      </SomeContext.Provider>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

新的HTML输出

Context of ChildTwo: true
Context of ChildOne: true
Run Code Online (Sandbox Code Playgroud)

运行代码

static contextTypeProvider组件直接使用消耗其render()函数中的上下文的子组件时,为什么上下文API(> = v16.6)不起作用(使用)?这是一个错误还是一个已知的限制?我错过了什么?

附加信息

使用<SomeContext.Consumer>将按预期工作.

export default class ChildOne extends Component {
  public render(){
    return (
      <SomeContext.Consumer>
        {context =>
          <div>
          {`Context of ChildOne: ${context.someValue}`}
          </div>
        }
      </SomeContext.Consumer>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

当然,这不是解决这个问题的方法,但可能是一个有用的信息.

ysf*_*ran 2

我在 React github 上创建了一个问题,发现这不是一个 React Bug,而是一个 Javascript/Typescript 问题。

概括

错误的导入顺序导致了“错误”。因为是在声明上下文之前ChildOne导入 (in ) 的,实际上是在导入时导入的。ParentWithContextSomeContextundefinedChildOne

import ChildOne from "./ChildOne";

export const SomeContext = React.createContext({
  someValue: false
});
Run Code Online (Sandbox Code Playgroud)

所以一种解决方案是交换这两个声明

export const SomeContext = React.createContext({
  someValue: false
});

import ChildOne from "./ChildOne";
Run Code Online (Sandbox Code Playgroud)

或者简单地(恕我直言,更干净)将上下文提取到它自己的文件中。这样您就可以排除将来出现任何类似问题。