问题
I'm trying to implement a react-table using this guide:
https://github.com/tannerlinsley/react-table/blob/master/docs/quickstart.md
At one point in the guide, it says to create your data using React.useMemo:
const columns = React.useMemo(
() => [
{
Header: 'Column 1',
accessor: 'col1', // accessor is the "key" in the data
},
{
Header: 'Column 2',
accessor: 'col2',
},
],
[]
)
When I do this, I copy and paste this line into my code (replacing the data with my own data):
class Blog extends Component {
...
createTable() {
const cols = React.useMemo(
// copy and paste here
);
// more table creation code
return (
// jsx for table
);
}
...
}
But when I run this, it tells me:
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
So after googling this problem, I gathered that I need to call useMemo in a React funcion. So I created this:
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;
And in my Blog class:
class Blog extends Component {
...
createTable() {
const cols = getCols();
// more table creation code
return (
// jsx for table
);
}
...
}
But now it tells me:
React Hook "React.useMemo" is called in function "getCols" which is neither a React function component or a custom React Hook function
Why isn't it a React function?
More importantly, what is the proper way to call useMemo(...)?
Thanks.
回答1:
The error messages aren't asking you to put the code in a "react function", they're asking you to put it into a "function component". Your code snippets are all class components (ie, they start with class XYZ extends Component
), and hooks (including useMemo
) do not work in class components.
Assuming you want to follow the steps in that tutorial, you'll need to write your code as function components, not class components.
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:
Why isn't it a React function?
It depends on the way you are using it. getCols()
is just a simple function call returning jsx
and React interprets it as so. You have to render
it to get React to interpret it as a functional component
const cols = <getCols />; // this would be a React functional component
More importantly, what is the proper way to call useMemo(...)?
First thing to understand is that there are two ways to define components in React - functional components or class components.
useMemo
is a hook. Hooks are used to add stateful logic to functional components. Class components, already have that with their lifecycle methods (like componentDidMount
, componentDidUpdate
). So hooks can only be used inside a functional component or another custom hook, as mentioned in the two warnings you got:
Hooks can only be called inside of the body of a function component.
React Hook "React.useMemo" is called in function "getCols" which is neither a React function component or a custom React Hook function
useMemo is used to memoize the value of something, based on the dependencies. Means once you assign something using useMemo
, the value/reference won't change till your dependencies update.
// `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
)
Since your component Blog
is a class component, you won't be able to use hooks inside it directly.
There are couple of ways to do so:
Method 1: Make Blog a functional component
Convert the whole Blog
component as a functional component. The docs that you've linked also seem to be using it this way
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
)
}
Method 2: Extract cols out into a functional component
Use it as part of another functional component
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
);
}
}
Method 3: Use it as a custom hook
Unnecessary, but just to demonstrate a custom hook (you'll still need to convert Blog
into a functional component)
For the docs
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.
const useTableCols = () => {
const cols = React.useMemo(() => {
...
}, [])
return cols
}
const Blog = () => {
const cols = useTableCols()
// do something with `cols`
}
回答3:
First make sure you've actually installed it.
npm install react-table
Second, make sure you are importing it:
import { useTable } from 'react-table'
Third, why not just look at the Examples provided(too much code here to copy/paste):
https://github.com/tannerlinsley/react-table/tree/master/examples/basic/src
来源:https://stackoverflow.com/questions/62462611/why-isnt-react-usememo-working-in-my-react-function