【问题标题】:How to correctly type render props in Flow?如何在 Flow 中正确输入渲染道具?
【发布时间】:2020-12-28 20:35:51
【问题描述】:

我不知道在使用渲染道具时如何正确键入 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);

【问题讨论】:

    标签: javascript reactjs flowtype


    【解决方案1】:

    您的第一个问题与Counter1 组件行有关

    export const Counter1: React.Node = ({ count, increment }) => {
    

    基本上是将 Counter1 键入为 React.Node,您真正想要的是一个像这样返回 React.Node 的函数

    export const Counter1 = ({ count, increment }): React.Node => {
    

    您与Counter2 相关的第二个问题与类型优先有关,其中每个模块导出都必须显式键入,以便流程可以以最高性能运行,您可以阅读更多关于它的信息here


    您在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 => {
    

    【讨论】:

    • 谢谢!如果我想正确输入带有 props 的功能组件,我将如何在流程中做到这一点?例如在 TS 中我可以这样做: const app: React.FC = () => {}; Flow 中的等价物是什么?
    • 这与您在上面所做的类似,这里是try。但是 Flow 在推理上比 TS 运行得更多,所以你不需要直接给变量一个类型,因为 flow 通过静态分析你的代码来确保可靠性。除非您有一些由于某种原因返回 any 的代码,否则您可能需要提供一种类型来获得智能感知和健全性检查
    • 另外,如果此答案解决了您的问题,请记住标记为已回答以帮助其他人:)
    猜你喜欢
    • 2019-05-11
    • 2022-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-02
    • 1970-01-01
    • 2021-02-07
    相关资源
    最近更新 更多