当我尝试渲染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,
};
答案 0 :(得分:4)
答案 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
中未定义的属性/键,流程将抛出错误。>