【问题标题】:New React context API and flow error, when trying to render Consumer尝试呈现消费者时出现新的 React 上下文 API 和流错误
【发布时间】:2018-11-14 22:10:59
【问题描述】:

当我尝试渲染消费者时,流程显示下一个错误:

[流程] 无法创建 SidebarContextConsumer 元素,因为属性 children 的第一个参数的未定义 [1] 中缺少属性 changeOpenState。 (参考文献:[1])

这是我的代码:

// @flow
import React, { createContext } from 'react';

import type { Context, ProviderProps } from './Sidebar.types';

const SidebarContext = createContext();

export const SidebarContextConsumer = SidebarContext.Consumer;

/* eslint-disable react/no-unused-state */
export class SidebarContextProvider extends React.Component<ProviderProps, Context> {

  state = {
    dynamic: false,
    open: false,
    transition: false,
    changeDynamicMode: (dynamic: boolean) => {
      this.setState({
        dynamic,
        open: false,
        transition: false,
      });
    },
    changeOpenState: (open: boolean, transition: boolean = true) => {
      this.setState({ open, transition });
    },
  };

  render() {
    const { children } = this.props;

    return (
      <SidebarContext.Provider value={this.state}>
        {children}
      </SidebarContext.Provider>
    );
  }

}
/* eslint-enable */

流程声明:

export type Context = {
  changeDynamicMode: (dynamic: boolean) => void,
  changeOpenState: (open: boolean, transition?: boolean) => void,
  dynamic: boolean,
  open: boolean,
  transition: boolean,
};

【问题讨论】:

    标签: reactjs flowtype


    【解决方案1】:

    使用流,这就是我通常输入上下文的方式(没有初始值):

    const SidebarContext = createContext&lt;Context | typeof undefined&gt;();

    其中Context 是您自定义的type

    exact type 用于您的Context 也可能有用,因此如果有人尝试使用Context type 中未定义的属性/键,流将引发错误。

    【讨论】:

      【解决方案2】:

      以下内容适合我

      export const SidebarContextConsumer = ((SidebarContext.Consumer: any):
        React$ComponentType<{
          children: (value: Context) => ?React$Node
        }>
      );
      

      我已经转换了任何并恢复了原始的 Consumer typedef,但可能删除了值的类型

      React$ComponentType<{ children: (value: ?Context) => ?React$Node}>
      

      【讨论】:

        【解决方案3】:

        好像是known limitation的flowtype。

        我解决了我的错误:

        const SidebarContext: Object = createContext();
        

        【讨论】:

          【解决方案4】:

          TL;DR 这可以通过将默认值添加到 createContext 来解决

          我认为问题在于 Flow 与 React.createContext() 的交互方式存在逻辑缺陷。首先,我们可以使用React.Context&lt;myObject&gt; 指定上下文值。不幸的是,如果我们没有指定默认参数,Flow 正确会意识到myObject 可以是undefined

          一个简单的测试用例,您可以在Try Flow 玩:

          导入 * as React from 'react';

          type obj = {| a: string, b: number |}
          const ctxt: React.Context<?obj> = React.createContext();
          
          const cmpnt = () => (
            <ctxt.Provider value={{ a: "a", b: 2 }}>
              <ctxt.Consumer>
                {({a}) => console.log(a.toUpperCase())}
              </ctxt.Consumer>
            </ctxt.Provider>);
          

          正如您在 Flow 0.78 中看到的错误:

          {({a}) => console.log(a.toUpperCase())}
           ^ Cannot create `ctxt.Consumer` element because property `a` is missing in null or undefined [1] in the first argument of property `children`.
          
          References:
          
          4: const ctxt: React.Context<?obj> = React.createContext();
          

          如果我们添加default,它就会消失:

          import * as React from 'react';
          
          type obj = {| a: string, b: number |}
          const ctxt: React.Context<obj> = React.createContext({ a: "test", b: 2 });
          
          const cmpnt = () => (
            <ctxt.Provider value={{ a: "a", b: 2 }}>
              <ctxt.Consumer>
                {({a}) => console.log(a.toUpperCase())}
              </ctxt.Consumer>
            </ctxt.Provider>);
          

          对原始问题的建议修复

          import * as React from 'react';
          
          type Context = {
            changeDynamicMode: (dynamic: boolean) => void,
            changeOpenState: (open: boolean, transition?: boolean) => void,
            dynamic: boolean,
            open: boolean,
            transition: boolean,
          };
          
          const defaultState: Context = {
            dynamic: false,
            open: false,
            transition: false,
            changeDynamicMode: (dynamic: boolean) => console.error('Fix function!', dynamic),
            changeOpenState: (open: boolean, transition: boolean = true) => console.error('Fix function!', open, transition),
          }
          
          const ctxt = React.createContext(defaultState);
          
          class SidebarContextProvider extends React.Component<mixed & { children: React.Node }, Context> {
          
            state = {
              dynamic: false,
              open: false,
              transition: false,
              changeDynamicMode: (dynamic: boolean) => {
                this.setState({
                  dynamic,
                  open: false,
                  transition: false,
                });
              },
              changeOpenState: (open: boolean, transition: boolean = true) => {
                this.setState({ open, transition });
              },
            };
          
            render() {
              const { children } = this.props;
          
              return (
                <ctxt.Provider value={this.state}>
                  {children}
                </ctxt.Provider>
              );
            }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2022-08-08
            • 1970-01-01
            • 2021-12-25
            • 1970-01-01
            • 1970-01-01
            • 2018-09-22
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多