Помилка React Hooks: Хуки можна викликати лише всередині тіла функціонального компонента


78

Я отримую цю помилку під час використання useStateгачка. Я маю це в базовій формі, дивлячись на реакційні документи для посилання, але все ще отримую цю помилку. Я готовий до моменту долоні обличчя ...

export function Header() {
  const [count, setCount] = useState(0)
  return <span>header</span>
}

2
Працює у мене ... без помилок ... ви оновили до 16.7?
SakoBu

Так, я зробив. Я думаю, можливо, це пов’язано з моїм налаштуванням, але я не знаю, що. Подія, якщо я використовую той самий гачок у верхній частині функції компонента App, я отримую ту ж помилку.
loganfromlogan

Хм-м-м-м ... все, що я зробив, це npx create-response-app newhook, а потім пряжа, додайте реагувати @ next і реагувати-dom @ next, і це спрацювало чудово ...
SakoBu

8
Просто FYI для тих, хто опинився тут, вам потрібно оновити React і ReactDOM до @next, щоб гачки працювали. Якщо ви цього не зробите, реакція викине вищевказану помилку. Я знаю, тому що у мене щойно була ця проблема, і це було моє рішення.
Тоні

Відповіді:


40

Оновлено: 2018-груд

react-hot-loaderЗараз вийшла нова версія , посилання . Гачки зараз працюють нестандартно. Дякую автору, Каші.

Ознайомтеся з цим типовим шаблоном https://github.com/ReeganExE/react-hooks-boilerplate

  • Гаки для реагування
  • Гарячий навантажувач React
  • Webpack, Babel, ESLint Airbnb

Попередня відповідь:

Спочатку переконайтеся, що ви встановили react@nextтаreact-dom@next .

Тоді перевірте, react-hot-loaderчи використовуєте ви чи ні.

У моєму випадку вимкніть гарячий завантажувач, і HMR може змусити його працювати.

Див. Https://github.com/gaearon/react-hot-loader/issues/1088 .

Цитується:

Так. RHL на 100% не сумісний з гачками. За цим є лише кілька причин:

SFC перетворюються на компоненти класу. Є причина - мати можливість примусово оновити HMR, поки на SFC не існує методу "оновлення". Я шукаю інший спосіб примусового оновлення (наприклад, так. Тож RHL вбиває SFC.

"hotReplacementRender". RHL намагається виконати роботу React та відтворити стару та нову програму, щоб об'єднати їх. Тож, очевидно, зараз це зламано.

Я збираюся скласти PR, щоб пом'якшити обидві проблеми. Це спрацює, але не сьогодні.

Існує більш правильне виправлення, яке могло б працювати - холодний API

Ви можете вимкнути RHL для будь-якого нестандартного типу.

import { cold } from 'react-hot-loader';

cold(MyComponent);

Шукайте "useState/useEffect"всередині вихідного коду компонента і "холодно" його.

Оновлено:

Відповідно до оновлення, яке додав реагент-гарячий завантажувач, ви можете спробувати react-hot-loader@nextвстановити конфігурацію нижче:

import { setConfig } from 'react-hot-loader';

setConfig({
  // set this flag to support SFC if patch is not landed
  pureSFC: true
});

Дякуємо @loganfromlogan за оновлення.


Дякуємо, що вказали на це :). Я використовую реактор-гарячий завантажувач, тому було б зрозуміло, що він не працює. Однак я ще не впевнений на 100%, що щось інше теж не відбувається. Я збираюся стежити за цією проблемою в реакції-hot-loader, і оновлю це питання після опублікування виправлення.
loganfromlogan

Тепер я можу підтвердити, що вимкнення реактор-гарячого завантажувача вирішило цю помилку.
loganfromlogan

2
Додамо, якщо випадково ви надаєте свій компонент як вбудований виклик функції jsx, це все одно спричинить помилку, навіть коли компонент обгорнуто cold. Так {MyComponent(props)}не буде працювати, але <MyComponent {...props} />буде.
Dimitar Nikovski

Зараз є спосіб змусити це працювати з реакцією-гарячим завантажувачем. Зверніться до цього коментаря від супровідника response
loganfromlogan

32

Моя проблема полягала в тому, що я забув оновити react-domмодуль. Див. Випуск .


3
Я також! Я використовую create-response-app та Typescript
jugglingcats

1
Я використовую версію 16.8.3 реагувати і реагувати-dom, але все одно маю таку ж проблему
huykon225

16

Був той самий випуск. Моя проблема була пов'язана з React Router. Я випадково використовував

<Route render={ComponentUsingHooks} />

замість

<Route component={ComponentUsingHooks} />

1
цей коментар також врятував мені життя. На це витратив 3 години і розірвав мій проект на шматки. Був друкарська помилка в маршрутизаторі
Бен Ганневей

3

Я зміг це вирішити, імпортуючи примітивні хуки React у файл компонента, а потім передавши їх у мої власні хуки. З якоїсь причини помилка виникає лише тоді, коли я імпортую гачок React (наприклад, useState) у своєму користувацькому файлі хука.

Я імпортую useState у файл компонента:

import React, {useState} from 'react'; // import useState

import {useCustomHook} from '../hooks/custom-hook'; // import custom hook

const initialState = {items: []};
export default function MyComponent(props) {
    const [state, actions] = useCustomHook(initialState, {useState});
    ...
}

Потім у моєму файлі хука:

// do not import useState here

export function useCustomHook(initialValue, {useState}) {
    const [state, setState] = useState(initialValue || {items: []});

    const actions = {
        add: (item) => setState(currentState => {
            const newItems = currentState.items.concat([item]);
            return {
                ...currentState,
                items: newItems,
            };
        }),
    };

    return [state, actions];
}

Цей метод покращив перевірку моїх хуків, тому що мені не потрібно глузувати з бібліотеки React, щоб надати примітивні хуки. Натомість ми можемо передати фіктивний useStateгачок прямо у функцію користувацького гачка. Я думаю, це покращує якість коду, оскільки ваші власні хуки тепер не пов'язані з бібліотекою React, що дозволяє більш природне функціональне програмування та тестування.



3

У мене була проблема в monorepo, де пакет docz використовуєтьсяreact@16.6.3 і остаточний висновок пучка мав дві версії реагувати.

Випуск на Github

Виправлено, видаливши пакет 😅


2

Проблемою для мене справді була реакція гарячого завантажувача .

Ви можете вимкнути реакцію гарячого завантажувача для одного компонента замість усієї програми, використовуючи такий coldспосіб:

import { cold } from 'react-hot-loader'

export const YourComponent = cold(() => {

  // ... hook code

  return (
    // ...
  )
})

АБО

export default cold(YourComponent)

2

Просто розробити на @ rista404 відповідає, в тому числі дубльованих версій з react(і , можливо react-dom) дасть ту ж помилку , в залежності від того, де ви використовуєте свої гачки. Ось два приклади ...

  1. Зовнішня залежність включає в себе іншу версію reactв її dependencies, швидше за все , помилково , як reactправило , повинна бути рівноправною залежністю. Якщоnpm ця версія не виводиться автоматично з вашої локальної версії, ви можете побачити цю помилку. Ось на що мав на увазі @ rista404.
  2. Ви npm linkпакет, який включає reactв себе devDependenciesабо dependencies. Тепер для модулів цього пакету ви можете побачити помилки, якщо вони витягують іншу версію файлу reactз локального node_modulesкаталогу, а не батьківського проекту.

Останнє можна виправити при поєднанні webpack, використовуючи resolve.aliasяк так ...

    resolve: {
        alias: {
            'react': path.resolve(__dirname, 'node_modules/react'),
            'react-dom': path.resolve(__dirname, 'node_modules/react-dom')
        }
    }

Це забезпечить reactзавжди витягування з node_modulesкаталогу батьківського проекту .


2

Для тих, хто стикається з цією проблемою під час використання MobX та обгортання компонента значком observer, обов’язково використовуйте mobx-react-liteзамість mobx-react.

29 ТРАВНЯ ОНОВЛЕННЯ

Від mobx-react 6.0.0вперед, компоненти на основі гака тепер підтримуються mobx реагують , таким чином, немає необхідності в mobx-react-liteвикористанні більше (якщо це ваша проблема).


1

знайшов це обхідне рішення, react-hot-loaderпоки цей PR, щоб виправити його, є вхідним.

Оберніть функцію, яка викликає хуки, у React.memo, запобігаючи гарячому перезавантаженню, якщо вона не змінюється.

const MyFunc = React.memo(({props}) => {...

Кредит на рішення: https://github.com/gatsbyjs/gatsby/issues/9489


1

Моє питання було наступним:

Я робив: ReactDOM.render(Example(), app);

Тоді як я повинен був робити: ReactDOM.render(<Example />, app);


1
Це теж була моя проблема, і я радий знайти її серед відповідей тут.
Сет Бро

Це теж була моя проблема, і я радий знайти її серед відповідей тут. Я підозрював, що це буде якась тонка дурість з моєї власної справи, але, оскільки явно є деякі реальні проблеми з дублюванням модулів у пакетах , я пішов у 4-годинну кролячу нору дослідницького гніву. Щасливий відновити мій розум ціною моєї гордості.
Сет Бро

1

Для інших користувачів робочих областей пряжі, ось моя ситуація та як я це зрозумів.

  • пакунки
    • foo
      • реагувати@16.8.6
    • бар
      • реагувати@16.10.1

Документи Facebook щодо попередження про недійсний дзвінок на хук нічого не говорять про робочі простори пряжі, тому я припустив, що моя конфігурація була правильною. Але це не було. Виправити помилку можна лише використовуючи ту саму версію для всіх ваших пакетів .

У наведеному вище прикладі вам потрібно встановити версію реакції з "foo" на 16.10.1, щоб вона відповідала версії реакції з "bar".

Бонус: перегляньте цю дискусію на GitHub щодо чудової колекції емоційного багажу, вивантаженого в Інтернеті.


1

Ще одне рішення, якщо ви стикаєтесь із цим при використанні посилання npm:

Ви можете npm linkреагувати у своїй бібліотеці, як пояснено тут: https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react

або встановіть реакцію у вашій бібліотеці як peerDependency, а потім використовуйте npm link --only=production


0

Якщо ви використовуєте Create React App, вам доведеться оновити "react-scripts"версію також за допомогою React і React -Dom версії.

 "react-scripts": "2.1.5",
 "react": "^16.8.1",
 "react-dom": "^16.8.1",

ця комбінація чудово працює.




-5

оновити пакет.json версія-dom-реакція як реакція


"реагувати": "^ 16.7.0-альфа.0", "реагувати-дом": "^ 16.7.0-альфа.0",
shisongyan

5
Якщо відповідь - лише пропозиція, ви можете скористатися розділом коментарів
AirCodeOne
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.