如何在 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 => {