Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@shinnoki

monorepoでReact Hooksを使うライブラリを使うとInvariant Violationエラーになった

More than 1 year has passed since last update.

環境

  • react-native 0.59.5
  • react 16.8.3
  • apollo-client 2.4.6
  • react-apollo 2.5.4
  • react-apollo-hooks 0.4.5

yarn workspaceを使ってmonorepoとして運用している。

sampleProject
  ├── packages
  │   ├── core
  |   |   └── ...
  │   ├── app (React Native)
  |   |   ├── ...
  |   |   ├── package.json
  |   |   └── node_modules
  |   |       └── ...
  |   └── ...
  ├── package.json
  ├── yarn.lock
  └── node_modules
      └── ...

yarn workspace内でReact Nativeを動かすとき、プロジェクトレベルのnode_modulesにreact-nativeがインストールされてしまうと react-native コマンドが正常に動かない。yarn workspaceのnohoistの設定でreact-nativeを指定することでプロジェクトレベルではなくパッケージレベルのnode_modulesにインストールすることでこの問題を解決している。

参考: nohoist in Workspaces | Yarn Blog

package.json
{
  "name": "sampleProject",
  "private": true,
  "workspaces": {
    "packages": [
      "packages/*"
    ],
    "nohoist": [
      "**/react-native",
      "**/react-native/**"
    ]
  }
}

発生した問題

react-apollo-hooks を使おうとすると、Function Component内で使用したにも関わらず以下のようなエラーになる。

Invariant Violation: Hooks can only be called inside the body of a function component. (https://fb.me/react-invalid-hook-call)
App.tsx
import React, { useState } from 'react';
import { useQuery } from 'react-apollo-hooks';

...

interface Props {}

const App: React.FC<Props> = props => {
  // Invariant Violationが発生する
  const { data, error, loading } = useQuery(SOME_QUERY);

  // こちらはエラーにならない
  const [count, setCount] = useState(0);

  ...
}

export default App;

原因と解決法

react モジュールが複数存在してしまっていたのが原因だった。
https://github.com/facebook/react/issues/13991
https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react

nohoistにreact-nativeを指定したことで、react-nativeが使用する react がパッケージレベルに、react-apollo-hooksが使用する react はプロジェクトレベルに存在する状態になっていた。

sampleProject
  ├── packages
  │   ├── app
  |   |   ├── ...
  |   |   └── node_modules
  |   |       ├── react <- パッケージレベル
  |   |       ├── react-native
  |   |       └── ...
  |   └── ...
  ├── node_modules
  |   ├── react <- プロジェクトレベル
  |   ├── react-apollo-hooks
  |   └── ...
  └── ...

これを解決するために、issueのコメントのようにreact-nativeが依存するreactをnohoistから除外することで、プロジェクトレベルに巻き上げた。

package.json
     "nohoist": [
       "**/react-native",
-      "**/react-native/**"
+      "**/react-native/!(react)/**"
     ]

まとめ

  1. yarn workspaceを使っている
  2. reactがnohoistの対象になっている(主にReact Nativeで起こる)
  3. ライブラリ内でReact Hooksを使っている

というかなり限定的な条件でしかこの問題は発生しませんが、ReduxもHooksを提供するっぽいので今後は似たようなハマり方が多くなるんじゃないかなと思いました。

5
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
wasd-inc
『意思疎通をもっと便利に』をミッションに掲げるスタートアップです。 呼び出し業務を革新するクラウドサービス『デジちゃいむ』を開発しています。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?