Почему React.useMemo(...) не работает в моей функции React?
Я пытаюсь реализовать таблицу реакций, используя это руководство:
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
Итак, после поиска этой проблемы я понял, что мне нужно вызвать useMemo в функции React. Итак, я создал это:
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;
И в моем классе блога:
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 ответа
Почему это не функция React?
Это зависит от того, как вы его используете. getCols()
это просто возврат простого вызова функции jsx
и React интерпретирует это так. Вы должныrender
чтобы заставить React интерпретировать его как функциональный компонент
const cols = <getCols />; // this would be a React functional component
Что еще более важно, как правильно вызывать useMemo(...)?
Первое, что нужно понять, это то, что есть два способа определить компоненты в React - функциональные компоненты или компоненты класса.
useMemo
это крючок. Хуки используются для добавления логики с отслеживанием состояния к функциональным компонентам. Компоненты класса уже имеют это с их методами жизненного цикла (например,componentDidMount
, componentDidUpdate
). Таким образом, хуки можно использовать только внутри функционального компонента или другого пользовательского хука, как упоминалось в двух полученных вами предупреждениях:
Хуки могут быть вызваны только внутри тела функционального компонента.
React Hook "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
компонент как функциональный компонент. Документы, которые вы связали, также, похоже, используют его таким образом
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
в функциональную составляющую)
Для документов
Пользовательский крючок - это функция JavaScript, имя которой начинается с "использовать" и которая может вызывать другие хуки.
const useTableCols = () => {
const cols = React.useMemo(() => {
...
}, [])
return cols
}
const Blog = () => {
const cols = useTableCols()
// do something with `cols`
}
Сообщения об ошибках не просят вас поместить код в "функцию реакции", они просят вас поместить его в "функциональный компонент". Все фрагменты кода являются компонентами класса (т. Е. Начинаются с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
);
};
Сначала убедитесь, что вы его действительно установили.
npm install react-table
Во-вторых, убедитесь, что вы его импортируете:
import { useTable } from 'react-table'
В-третьих, почему бы просто не взглянуть на предоставленные примеры (здесь слишком много кода для копирования / вставки):
https://github.com/tannerlinsley/react-table/tree/master/examples/basic/src