为什么React.useMemo(...)在我的React函数中不起作用?

时间:2020-06-19 03:04:25

标签: reactjs react-functional-component react-usememo

我正在尝试使用此指南来实现反应表:

https://github.com/tannerlinsley/react-table/blob/master/docs/quickstart.md

在指南中,它指出要使用React.useMemo创建数据:

const columns = React.useMemo(
  () => [
    {
      Header: 'Column 1',
      accessor: 'col1', // accessor is the "key" in the data
    },
    {
      Header: 'Column 2',
      accessor: 'col2',
    },
  ],
  []
)

执行此操作时,我将此行复制并粘贴到我的代码中(用我自己的数据替换数据):

class Blog extends Component {

...

createTable() {

    const cols = React.useMemo(
        // copy and paste here
    );

    // more table creation code

    return (
        // jsx for table
    );
}

...

}

但是当我运行它时,它告诉我:

Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app

因此,在搜索了这个问题之后,我收集到我需要在React函数中调用useMemo。所以我创建了这个:

import React from 'react';

const getCols = () => {
    return React.useMemo(() => [
        {
            Header: 'title',
            accessor: 'titleCol'
        },
        {
            Header: 'body',
            accessor: 'bodyCol'
        },
        {
            Header: 'last updated',
            accessor: 'updatedAtCol'
        }
    ], []);
};

export default getCols;

在我的Blog类中:

class Blog extends Component {

...

createTable() {

    const cols = getCols();

    // more table creation code

    return (
        // jsx for table
    );
}

...

}

但是现在它告诉我:

React Hook "React.useMemo" is called in function "getCols" which is neither a React function component or a custom React Hook function

为什么它不是React函数?

更重要的是,调用useMemo(...)的正确方法是什么?

谢谢。

3 个答案:

答案 0 :(得分:1)

为什么它不是React函数?

这取决于您的使用方式。 getCols()只是返回jsx的简单函数调用,React如此解释。您必须render才能使React解释为功能组件

 const cols = <getCols />; // this would be a React functional component

更重要的是,调用useMemo(...)的正确方法是什么?

首先要了解的是,有两种方法可以在React中定义组件-functional components or class components

useMemohook。挂钩用于向功能组件添加状态逻辑。类组件已经具有其生命周期方法(例如componentDidMountcomponentDidUpdate)。因此,挂钩只能只能在功能组件或另一个自定义挂钩中使用,如您收到的两个警告所述:

只能在函数组件的主体内部调用钩子。

反应挂钩“ React.useMemo”在“ getCols”函数中调用,该函数既不是React函数组件也不是自定义的React Hook函数

useMemo用于根据相关性来记住某物的值。意味着一旦您使用useMemo分配了内容,值/引用就不会更改,直到您的依赖项更新为止。

   // `cols` will have the same value - `[ { Header: 'title ... ]`
   // TILL the dependency array changes
   const cols = React.useMemo(() => [
        {
            Header: 'title',
            accessor: 'titleCol'
        },
        {
            Header: 'body',
            accessor: 'bodyCol'
        },
        {
            Header: 'last updated',
            accessor: 'updatedAtCol'
        }
    ], 
    [] // <-- this is the dependency array, 
    // since it's empty, `cols` will only be initialized once

    // if you had something like this instead
    // [numberOfCols] 
    // i.e a variable in the dependency array, 
    // `cols` would update everytime `numberOfCols` updated
   )

由于组件Blog是类组件,因此您将无法直接在其内部使用钩子。

有两种方法可以做到:

方法1:使Blog成为功能组件

将整个Blog组件转换为功能组件。您链接的文档似乎也在以这种方式使用

const Blog = () => {
    // now you can use `cols` somewhere in the body of your component
    const cols = React.useMemo(() => { 
      ...
    }, [])


    // this will return whatever you were returning from the 
    // `render` function in class component
    return (
      // jsx for table
    )
}

方法2:将cols提取到功能组件中

将其用作其他功能组件的一部分

class Blog extends Component {


 createTable() {
    // `cols` will be a React component now, not an array
    // so probably not what you need,
    // unless you want to use cols within that function
    // and return the `jsx` to be rendered directly
    const cols = <getCols />;

    // more table creation code

    return (
        // jsx for table
    );
  }

}

方法3:将其用作自定义钩子

不必要,但只是为了演示自定义钩子(您仍然需要将Blog转换为功能组件)

对于docs

自定义挂钩是一个JavaScript函数,其名称以“ use”开头,并且可以调用其他挂钩。

const useTableCols = () => {
   const cols = React.useMemo(() => {
     ...
   }, [])

   return cols
}


const Blog = () => {
   const cols = useTableCols()
   
   // do something with `cols`
}

答案 1 :(得分:0)

错误消息不是要您将代码放入“反应功能”中,而是要您将其放入“功能组件”中。您的代码段都是类的所有组件(即,它们以class XYZ extends Component开头),并且钩子(包括useMemo)在类组件中不起作用。

假设您要按照该教程中的步骤进行操作,则需要将代码编写为功能组件,而不是类组件。

const Blog = (props) => {
  const cols = React.useMemo(() => [
    {
      Header: "title",
      accessor: "titleCol",
    },
    {
      Header: "body",
      accessor: "bodyCol",
    },
    {
      Header: "last updated",
      accessor: "updatedAtCol",
    },
  ], []);

  // more table creation code

  return (
    // jsx for table
  );
};

答案 2 :(得分:-1)

首先请确保您已经安装了它。

npm install react-table

第二,请确保您正在导入它:

import { useTable } from 'react-table'

第三,为什么不只看提供的示例(此处要复制/粘贴的代码太多):

https://github.com/tannerlinsley/react-table/tree/master/examples/basic/src