如何在 Flow 中正确输入渲染道具?
How to correctly type render props in Flow?
我不知道在使用 render props 时如何正确键入 Wrapper 和 Counter 组件。我尝试了以下方法,但它只会导致更多错误:
App.js
// @flow
const App = (): React.Node => {
return (
<div className="App">
<Wrapper render={(count, increment) => {
return <Counter1 count={count} increment={increment}/>
}}/>
<Wrapper render={(count, increment) => {
return <Counter2 count={count} increment={increment} />
}}/>
</div>
);
};
Wrapper.js
// @flow
import * as React from 'react';
type WrapperProps<T> = {
render: T => React.Node
};
export const Wrapper = <T>({render}): Props<T> => {
const [count, setCount] = React.useState<number>(0);
const increment = (prevCount: number) => setCount(count + 1);
return (
<div>
{render(count, increment)}
</div>
);
}
Counter1.js
// @flow
import * as React from 'react';
export const Counter1: React.Node = ({ count, increment }) => {
return (
<>
<div>Counter 1: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
Counter2.js
// @flow
import * as React from 'react';
export const Counter2 = ({ count, increment }) => {
return (
<>
<div>Counter 2: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
我目前有 14 个错误,我真的迷路了。我不知道如何输入 Wrapper props 和 counter props。以下是一些错误:
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because $Iterable [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Element [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Portal [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because boolean [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because null [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because number [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter1.js:4:37
Cannot assign function to Counter1 because: [incompatible-type]
• Either inexact function [1] is incompatible with exact object type [2].
• Or function [1] is incompatible with React.Portal [3].
• Or property @@iterator is missing in function [1] but exists in $Iterable [4].
src/components/Counter1.js
1│ // @flow
2│ import * as React from 'react';
3│
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 1: {count}</div>
8│ <button onClick={increment}>Increment</button>
9│ </>
10│ );
11│ };
12│
/private/tmp/flow/flowlib_1fa18dde633e97c7_501/react.js
[2] 18│ | React$Element<any>
[3] 19│ | React$Portal
[4] 20│ | Iterable<?React$Node>;
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:26
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:47
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at function return: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:28
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:39
Cannot resolve name Props. [cannot-resolve-name]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
您的第一个问题与 Counter1
组件行有关
export const Counter1: React.Node = ({ count, increment }) => {
这基本上是将 Counter1 键入 React.Node,您真正想要的是 RETURNS 和 React.Node 这样的函数
export const Counter1 = ({ count, increment }): React.Node => {
您与 Counter2
相关的第二个问题首先与类型相关,其中每个模块导出都必须显式键入,以便流程可以 运行 发挥最大性能,您可以阅读更多相关信息 .
你在 Wrapper
组件中的最后一个问题与你有一个名为 WrapperProps
的类型有关,但你将其用作 Props
所以它说它可以找到它。另外我相信你把你的 WrappedProps
放在了错误的地方,所以把它从
export const Wrapper = <T>({render}): Props<T> => {
到
export const Wrapper = <T>({render}: Props<T>): React.Node => {
尽管回想起来您可能想考虑父组件将如何实际使用它并传入泛型,因为您的渲染函数已经需要两个参数,所以泛型在这里不是很有用。根据您的代码,您可能想要这样的东西
type WrapperProps = {
render: (
number,
(number) => void,
) => React.Node,
};
export const Wrapper = ({render}: WrapperProps): React.Node => {
我不知道在使用 render props 时如何正确键入 Wrapper 和 Counter 组件。我尝试了以下方法,但它只会导致更多错误:
App.js
// @flow
const App = (): React.Node => {
return (
<div className="App">
<Wrapper render={(count, increment) => {
return <Counter1 count={count} increment={increment}/>
}}/>
<Wrapper render={(count, increment) => {
return <Counter2 count={count} increment={increment} />
}}/>
</div>
);
};
Wrapper.js
// @flow
import * as React from 'react';
type WrapperProps<T> = {
render: T => React.Node
};
export const Wrapper = <T>({render}): Props<T> => {
const [count, setCount] = React.useState<number>(0);
const increment = (prevCount: number) => setCount(count + 1);
return (
<div>
{render(count, increment)}
</div>
);
}
Counter1.js
// @flow
import * as React from 'react';
export const Counter1: React.Node = ({ count, increment }) => {
return (
<>
<div>Counter 1: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
Counter2.js
// @flow
import * as React from 'react';
export const Counter2 = ({ count, increment }) => {
return (
<>
<div>Counter 2: {count}</div>
<button onClick={increment}>Increment</button>
</>
);
};
我目前有 14 个错误,我真的迷路了。我不知道如何输入 Wrapper props 和 counter props。以下是一些错误:
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because $Iterable [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Element [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because React.Portal [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because boolean [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because null [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/App.js:35:17
Cannot create Counter1 element because number [1] is not a React component. [not-a-component]
src/App.js
32│ </div>
33│ ))}
34│ <Wrapper render={(count, increment) => {
35│ return <Counter1 count={count} increment={increment}/>
36│ }}/>
37│
38│ <Wrapper render={(count, increment) => {
src/components/Counter1.js
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter1.js:4:37
Cannot assign function to Counter1 because: [incompatible-type]
• Either inexact function [1] is incompatible with exact object type [2].
• Or function [1] is incompatible with React.Portal [3].
• Or property @@iterator is missing in function [1] but exists in $Iterable [4].
src/components/Counter1.js
1│ // @flow
2│ import * as React from 'react';
3│
[1] 4│ export const Counter1: React.Node = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 1: {count}</div>
8│ <button onClick={increment}>Increment</button>
9│ </>
10│ );
11│ };
12│
/private/tmp/flow/flowlib_1fa18dde633e97c7_501/react.js
[2] 18│ | React$Element<any>
[3] 19│ | React$Portal
[4] 20│ | Iterable<?React$Node>;
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:26
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Counter2.js:4:47
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at function return: [signature-verification-failure]
1│ // @flow
2│ import * as React from 'react';
3│
4│ export const Counter2 = ({ count, increment }) => {
5│ return (
6│ <>
7│ <div>Counter 2: {count}</div>
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:28
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type
annotation at array pattern: [signature-verification-failure]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ src/components/Wrapper.js:8:39
Cannot resolve name Props. [cannot-resolve-name]
5│ render: T => React.Node
6│ };
7│
8│ export const Wrapper = <T>({render}): Props<T> => {
9│ const [count, setCount] = React.useState<number>(0);
10│
11│ const increment = (prevCount: number) => setCount(count + 1);
您的第一个问题与 Counter1
组件行有关
export const Counter1: React.Node = ({ count, increment }) => {
这基本上是将 Counter1 键入 React.Node,您真正想要的是 RETURNS 和 React.Node 这样的函数
export const Counter1 = ({ count, increment }): React.Node => {
您与 Counter2
相关的第二个问题首先与类型相关,其中每个模块导出都必须显式键入,以便流程可以 运行 发挥最大性能,您可以阅读更多相关信息
你在 Wrapper
组件中的最后一个问题与你有一个名为 WrapperProps
的类型有关,但你将其用作 Props
所以它说它可以找到它。另外我相信你把你的 WrappedProps
放在了错误的地方,所以把它从
export const Wrapper = <T>({render}): Props<T> => {
到
export const Wrapper = <T>({render}: Props<T>): React.Node => {
尽管回想起来您可能想考虑父组件将如何实际使用它并传入泛型,因为您的渲染函数已经需要两个参数,所以泛型在这里不是很有用。根据您的代码,您可能想要这样的东西
type WrapperProps = {
render: (
number,
(number) => void,
) => React.Node,
};
export const Wrapper = ({render}: WrapperProps): React.Node => {