facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.32k stars 46.96k forks source link

[lerna] Invariant Violation: Hooks can only be called inside the body of a function component. #15097

Closed ppinel closed 5 years ago

ppinel commented 5 years ago

Hello,

I have an error regarding hooks in a lerna architecture project where we import a ux lib made of style component inside a react project. If component are host in the same app, error is not thrown.

Do you want to request a feature or report a bug? Report a bug

What is the current behavior?

An error is thrown:

Invariant Violation: Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)
    at invariant (http://localhost/static/js/main.chunk.js:121537:23)
    at resolveDispatcher (http://localhost/static/js/main.chunk.js:122922:36)
    at useRef (http://localhost/static/js/main.chunk.js:122956:28)
    at useStateWithGetter (http://localhost/static/js/main.chunk.js:39121:71)
    at useField (http://localhost/static/js/main.chunk.js:39161:35)
    at http://localhost/static/js/main.chunk.js:39417:27
    at renderWithHooks (http://localhost/static/js/0.chunk.js:70682:22)
    at mountIndeterminateComponent (http://localhost/static/js/0.chunk.js:72686:17)
    at beginWork (http://localhost/static/js/0.chunk.js:73237:20)
    at performUnitOfWork (http://localhost/static/js/0.chunk.js:77166:16)
    at workLoop (http://localhost/static/js/0.chunk.js:77207:28)
    at renderRoot (http://localhost/static/js/0.chunk.js:77287:11)
    at performWorkOnRoot (http://localhost/static/js/0.chunk.js:78232:11)
    at performWork (http://localhost/static/js/0.chunk.js:78142:11)
    at performSyncWork (http://localhost/static/js/0.chunk.js:78116:7)
    at requestWork (http://localhost/static/js/0.chunk.js:77971:9)
    at scheduleWork (http://localhost/static/js/0.chunk.js:77778:9)
    at scheduleRootUpdate (http://localhost/static/js/0.chunk.js:78482:7)
    at updateContainerAtExpirationTime (http://localhost/static/js/0.chunk.js:78508:14)
    at updateContainer (http://localhost/static/js/0.chunk.js:78576:14)
    at ReactRoot.push../node_modules/react-dom/cjs/react-dom.development.js.ReactRoot.render (http://localhost/static/js/0.chunk.js:78889:7)
    at http://localhost/static/js/0.chunk.js:79041:18
    at unbatchedUpdates (http://localhost/static/js/0.chunk.js:78359:14)
    at legacyRenderSubtreeIntoContainer (http://localhost/static/js/0.chunk.js:79037:9)
    at Object.render (http://localhost/static/js/0.chunk.js:79112:16)
    at boot (http://localhost/static/js/main.chunk.js:207505:52)
    at http://localhost/static/js/main.chunk.js:207517:10

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem. Your bug will get fixed much faster if we can run your code and it doesn't have dependencies other than React. Paste the link to your JSFiddle (https://jsfiddle.net/Luktwrdm/) or CodeSandbox (https://codesandbox.io/s/new) example below: Use this public repo and follow the readme. It's a good representation of our project's architecture. You will experience the error.

What is the expected behavior? Not throwing an error about hooks and displaying a working form.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React? Well, didn't tested before 16.8.0. But using react-form instead of informed works. An issue has been open on informed repository. II have the feeling that it's more related to React than informed itself.

I am aware of this page but nothing worked.

kunukn commented 5 years ago

I would recommend to use this linter in the projects where hooks are used eslint-plugin-react-hooks This might catch some hooks usage errors.

I tried to follow the install guide, but maybe you have to do a little more to get it up. (at least for me)

Clone the repository in your computer Run command: npm install Run command npx lerna bootstrap In the packages/client run npm start You should see the error in the browser's console.

EDIT: I needed

kunukn commented 5 years ago
hook-error

This is what I see from the steps

ppinel commented 5 years ago

Hello, Thanks for testing.

The error you see is "normal", that the point of my issue.

aweary commented 5 years ago

@ppinel this error usually indicates that you have more than one copy of React in your bundle.

See: https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react

ppinel commented 5 years ago

@aweary I tried to install react at the root of the project and delete it in ux and client. I experienced the same error. I will investigate further and come back here whether I fixed the issue or not.

ppinel commented 5 years ago

@aweary I think this issue should be reopened. Different testing cases:

Do you have any idea on how to fix this ?

joshball commented 5 years ago

What is interesting here... is that you can still use React Hooks while Informed Text field fails. For instance, given the following code, you will get the Hooks can only be called inside the body of a function component error. But if you take out the <Text> element, everything, including the Hook example, works fine.

(And yes, I have styled-components in here as well. ;-)

export function Informed() {
    return (
        <section>
            <h2>InformedNotWorking</h2>
            <Form>
                {() => (
                    <div>
                        <label>
                            First name:
                            <Text field="name" />
                        </label>
                    </div>
                )}
            </Form>{' '}
        </section>
    );
}
function ReactHooksWorking() {
    const [count, setCount] = useState(0);
    return (
        <div>
            <h2>ReactHooksWorking</h2>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>Click me</button>
        </div>
    );
}
export const HooksPage: React.SFC<any> = (props: any) => {
    return (
        <div>
            <ReactHooksWorking />
            <Informed />
        </div>
    );
};
ppinel commented 5 years ago

Do you have your component using hooks in a different package imported in your react app? If I us informed in my react app without using it in my ux lib it's working. My case here is only about this error throwing when I move informed use to my ux lib. @aweary or someone else, please reopen this issue because it still lacking of solution !

joshball commented 5 years ago

@ppinel and @aweary Just a bit more information.

TL;DR

  1. informed is using hooks here.
  2. The hooks work fine in the same module, but not outside.

First, I am not sure if I am clear on something @ppinel said above:

I am not using any hooks, there are used in informed module. eslint module won't help.

However, I pulled over informed's Text element code and all the dependencies, and then instead of importing Textfrom informed, I imported it locally, and the code runs without issues. And two of the dependency files are using hooks (useFile and useFormApi) - see below

import { Form } from 'informed';
import Text from './IF/Text';
// import { Form, Text } from 'informed';

That is, I specifically copied the following files to my electron project:

asField.tsx
Context.tsx
Text.tsx
useFile.tsx
useFormApi.tsx

And one thing to note, since I saw an issue with HMR, I am using fusebox HMR in my project

kunukn commented 5 years ago

I suspect the issue is within UX, CLIENT setup somehow and where React is first loaded from UX/node_modules folder and then from CLIENT/node_modules and some mismatch happens somehow.

I followed this guide: https://reactjs.org/warnings/invalid-hook-call-warning.html

I ran npm ls react from CLIENT and got extraneous error

$ npm ls react @test-informed-hooks/client@0.1.0 /test-informed-hooks/packages/client └── react@16.8.4 extraneous npm ERR! extraneous: react@16.8.4 /temp/test-informed-hooks/packages/client/node_modules/react

I did the changes below but still got the hooks error.


By examining the UX build bundle I discovered that React was included. To not include react / react-dom in the UX bundle when it is build by Webpack, you could add this in UX webpack.config.js.

externals: {
    react: {
      root: 'React',
      commonjs2: 'react',
      commonjs: 'react',
      amd: 'react',
      umd: 'react',
    },
    'react-dom': {
      root: 'ReactDOM',
      commonjs2: 'react-dom',
      commonjs: 'react-dom',
      amd: 'react-dom',
      umd: 'react-dom',
    },
  },

Informed is imported both by UX and CLIENT. It is bundled in the UX build. It might possible also be bundled in the CLIENT bundle.

joshball commented 5 years ago

Just a heads up @ppinel. I have a lerna projecat that this was an issue on. I had looked into the npm ls and I too was having these extraneous errors, however, it was only reporting a single react installation (as extraneous) from the root. Because everything was hoisted, I didn't think to check any lower. Of course, after digging deeper, rimraffing the node_modules everywhere and reinstalling, I finally found that, indeed, there were two versions of react in my app. So, once i deleted the version that got installed locally, voila, it worked. That said, it does look like your not hooks code path are indeed using hooks, and rewriting that might help future work. I will through an issue on your repo.

ppinel commented 5 years ago

@joshball thanks for your help. I'll try to investigate further. @kunukn thanks for your help. I'll try what you suggested and update this issue.

ppinel commented 5 years ago

Hello, I have fixed the issue by setting react, react-dom and informed as dependencies at the root level of my mono repository. I am not using webpack anymore for my ui library but babel. Sorry for the delay! Thank you @joshball and @kunukn for your help.

fractaltheory commented 5 years ago

@ppinel I just wanted to add that I was facing a similar issue, though I wasn't using lerna (but I am using yarn workspaces). Moving react and react-dom dependencies to the project root also fixed this for me. Thank you 😄

jottenlips commented 5 years ago

This was resolved when I added --hoist to lerna run bootstrap. I think it was confused by react being in multiple node_modules folders.

ggunia commented 4 years ago

If somebody will find it useful I resolved this issue just by pulling react/react-dom in peerDependencies in my local package which was used in another package, deleting library's dist folder and rerunning project. P.S this is for lerna monorepos.

tettoffensive commented 4 years ago

@jottenlips Do you have a template repo you can share with me? I'm having trouble with my lerna monorepo with packages for react-native, react-native-web, and a shared components. The shared compoents throw this error with I use useState. I've tried your suggestion of --hoist, but that command fails for me: see https://github.com/lerna/lerna/issues/2583

jottenlips commented 3 years ago

@tettoffensive I am still working on linking the react-native part (react-spring is giving me issues), but checkout https://github.com/jottenlips/react-bones for a react-native-web storybook + CRA example.

dcy0701 commented 3 years ago

如果有人会发现它有用我只是拉解决了这个问题,react/react-dompeerDependencies参加了在另一个包用我的本地包,删除库的dist文件夹并重新运行项目。PS 这是针对 lerna monorepos 的。

If somebody will find it useful I resolved this issue just by pulling react/react-dom in peerDependencies in my local package which was used in another package, deleting library's dist folder and rerunning project. P.S this is for lerna monorepos.

works for me

kevinfarrugia commented 2 years ago

I have encountered this issue in a monorepo (using lerna) and resolved it by adding react and react-dom as an external inside Webpack of the "module" package (where react and react-dom should also be defined as peerDependencies.

    externals: ["react", "react-dom"],