jaredpalmer/tsdx

Can't use hooks when `react` & `react-dom` are dev dependencies

mkaradeniz opened this issue ยท 16 comments

Current Behavior

Thank you for this project!

I'm not sure if I missed or didn't understand something, but when choosing the react template, react & react-dom are added as dev dependencies. When you then try to use a hook inside your library, you get a react-invalid-hook-call error. It works fine when removing them as dev dependencies and running yarn again.

Example:

export const Thing = () => {
  const [fooBar, setFooBar] = React.useState('foo');

  return (
    <div onClick={() => setFooBar('bar')}>
      the snozzberries taste like {fooBar}
    </div>
  );
};

Expected behavior

I would expect the template to enable me to use hooks.

Suggested solution(s)

No idea if "just removing the dev dependencies" is the proper solution. It at least worked for me.

Your environment

Software Version(s)
TSDX 0.5.4
TypeScript 3.4.5
Browser Chrome 74.0.3729.108
npm/Yarn Yarn 1.12.3
Operating System MacOS 10.14.4
Guria commented

The right solution is to put react and react-dom to peerDependencies + devDependencies (to be able still develop and test library itself) and never in a regular dependencies.

That doesn't seem to fix it for me. I still get the same error.

Guria commented

have you tried to drop node_modules and lock files and reinstall deps?
devDeps + peerDeps in a library shouldn't lead to a duplicated react in node_modules.
Use npm ls react or yarn list react to check that you have no duplicates.

Yes, we should add react to peer deps and dev deps in the template and keep them as regular deps in the example directory. This is how I do it in Formik. IIRC Formik doesnโ€™t place react-dom as a peer dep, only a dev dep, so it can be used with react native.

peerdeps in v0.5.5 9f5c6de

I think I found the problem. I was testing it using yarn link and I couldn't get it to work without removing the devDependency. Publishing a package based on 0.5.5 and using that worked fine. Thanks you all!

Sorry. I did get it work in an CRA-Project with the published package. But creating a project based on 0.5.5, adding a hook, and then trying to use the component in the provided example setup is still not working for me. Am I doing something wrong? Repo: https://github.com/mkaradeniz/tsdx-hooks-problem-example

Facing the same problem; I don't think it is caused by tsdx itself - hooks are quite picky when multiple react instances are present - see facebook/react#14257. Tried doing the recommendations from there; Linked the package react using yarn link and added "react": "link:../node_modules/react" to package.json. Did not work for me.

The solution which worked for me:

  • remove package.json/tsconfig.json from example
  • install parcel as dev dependency in the package root.
  • re-point the import in example/index.tsx to 'src/index.tsx`.
  • start the example from the root with parcel example/index.html

Probably not perfect, but at least it works quite fast.

Yeah, the "react": "link:../node_modules/react" didn't work for me directly either. Only after installing the dependencies without react & react-dom and then adding "react": "link:../node_modules/react" & "react-dom": "link:../node_modules/react-dom" after installing works. At least as long you don't yarn again.

Thanks for your workaround!

You donโ€™t need to run yarn link if you build and import from the root

I had the same issue, @petyosi solution worked for me.

I think the solution I like best now is to use Parcel's alias like so:

  "name": "example",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "parcel index.html"
  },
  "dependencies": {
    "react-app-polyfill": "^1.0.0"
  },
  "alias": {
    "react": "../node_modules/react",
    "react-dom": "../node_modules/react-dom"
  },

  "devDependencies": {
    "@types/react": "^16.8.15",
    "@types/react-dom": "^16.8.4",
    "parcel": "^1.12.3",
    "typescript": "^3.4.5"
  }
}```

made a PR to do just that

This doesn't work if you're trying to deploy the example site to Netlify or something similar. Is there any other way to accomplish this?

True

@mikecousins you can always add a script to install the latest version of your lib