尝试呈现Consumer时,新的React上下文API和流错误

时间:2018-06-05 12:13:05

标签: reactjs flowtype

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

  

[flow]无法创建SidebarContextConsumer元素,因为属性changeOpenState的第一个参数中的undefined [1]中缺少属性children。 (参考文献:[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,
};

4 个答案:

答案 0 :(得分:4)

它似乎是流类型的known limitation

我解决了以下情况的错误:

const SidebarContext: Object = createContext();

答案 1 :(得分:0)

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

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

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

    从'react'导入*作为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>
    );
  }
}

答案 2 :(得分:0)

以下内容对我有用

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

我已经尝试了所有类型并还原了原始的Consumer typedef,但可能删除了值的类型

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

答案 3 :(得分:0)

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

const SidebarContext = createContext<Context | typeof undefined>();

其中 Context 是您自定义的 type

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