8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React を勉強してたら、急に ESLint に 'React' is defined but never used. と言われた話

Last updated at Posted at 2020-11-11

はじめに

Reactの学習はじめたけど、JSXもよくわからんな〜って方が対象です。

私自身、見切り発車で学習を進め、いよいよCustom Hookというときに少しだけエラーでハマったのでメモ。

この記事でわかること

  • 'React' is defined but never used. eslint@typescript-eslint/no-unused-vars)の対策と意味

構築環境

  • react: 17.0.1
  • typescript: 4.0.3
  • eslint: 7.12.1
  • @typescript-eslint/eslint-plugin: 4.6.1
  • @typescript-eslint/parser: 4.6.1

先に結論だけ

ざっくり言うと、

JSX表記が無いときはimport React from 'react';する必要がないということです。
Reactimportしないようにすれば、ESLintに怒られなくなります。

以上です。

これで理解できた方は、この記事を読む必要はもうありません!

ちょっと解説

Reactの勉強をしてると、つい思考停止でファイルの一行目からimport React from 'react';してませんか?

わたしです。

さて、今回の経緯を説明します。

1. 何が起こったか

React Hooksの勉強として、Hooksを使ってシンプルなカウントダウンタイマーアプリを作成しました。

そのあとHooksのロジック部分を、Custom Hookを使って新しいファイルに分離、作成したところでエラーが出ました。

ディレクトリ構成は以下のようなものを想定してください。

src/
 ├hooks/
   └use-timer.tsx
 ├App.tsx
 ├Timer.tsx

Timer.tsxのHooks部分を、use-timer.tsxに分離する感じです。

そして、エラーが起こった状態のuse-timer.tsxの中身を見てみます。

use-timer.tsx
import React, { useState, useEffect, useMemo, useCallback, useRef } from 'react';
// 'React' is defined but never used. eslint@typescript-eslint/no-unused-vars

export const useTimer = (limit: number): [number, boolean, () => void] => {
  const [timeLeft, setTimeLeft] = useState(limit);
  const primes = useMemo(() => getPrimes(limit), [limit]);
  const reset = useCallback(() => setTimeLeft(limit), [limit]);
  const tick = () => setTimeLeft((t) => t - 1);
  const timerId = useRef<NodeJS.Timeout>();

  useEffect(() => {
    // 省略
  }, []);

  return [timeLeft, primes.includes(timeLeft), reset];
};

たくさんHooksの処理がありますが、useTimerにまとめられています。それがCustom Hookです。

難しそうだけど便利だな〜と思っていたら、一行目でエラーが!

'React' is defined but never used. eslint@typescript-eslint/no-unused-vars)

え、こんだけReact Hooks使ってるファイルでReact使われてないわけないだろw

結果、使われていませんでした。

2. エラーの意味と対策

少し方向は違いますが、ぐぐったらこんな質問がありました。

引用元:https://stackoverflow.com/questions/56755952/do-you-really-need-to-import-react-when-creating-hooks-react-hooks

I saw the examples where https://reactjs.org/docs/hooks-custom.html they always do:

import React, { useState, useEffect } from 'react';
But React is not really used in the file, do we really need it and why?

訳)
「公式ドキュメントのCutom Hookの例ではimport Reactしてるけど、それって実際は使われてないですよね、ほんとうに必要なんですか?」

答え:

You will need React if you are rendering JSX.

訳)
「JSXをレンダリングするならReactは必要ですよ」

つまり、Reactライブラリをimportする必要があるのは、JSXを記述しているときなのでした。

私の場合は、ESLintが、JSXもないのにReactは必要ないですよ、と教えてくれていたのです。

もう一度use-timer.tsxの中身をよく見てみると、JSXはありません。

さあ、Reactを消しましょう。

use-timer.tsx
import { useState, useEffect, useMemo, useCallback, useRef } from 'react';

めでたしめでたし。

3. 補足:JSXとは?

冗長かもしれませんが、ちょっとそれだけだと意味がよくわかんないって方へ。

落ち着いて、JSXの正体を確認しましょう。

たとえば、Click!と書かれたsubmit属性のbutton要素を生成するコードを示します。
以下の2つは同じ意味です。

JSXの記法だと、

<Button type="submit">
  Click!
</Button>

これがJavaScriptにコンパイルされると、

React.createElement(
  'button',
  { type: 'submit' },
  'Click!'
);

なんと実は、JSXは、React.createElementというメソッドコールをすることで、オブジェクト生成していたのです。

これまでimport Reactしていたのは、JSXを使用するためだった!(何度でも言う)

まとめ

  • ReactとJSXの魔法に惑わされるな!
  • エラーメッセージがすべて教えてくれる
  • Qiita初投稿で記事書くの難しかったけど楽しい!

間違ってたら修正します。

参考資料

  1. りあクト! TypeScriptで始めるつらくないReact開発 第3版【Ⅱ. React基礎編】
  2. https://stackoverflow.com/questions/56755952/do-you-really-need-to-import-react-when-creating-hooks-react-hooks
  3. https://github.com/typescript-eslint/typescript-eslint/blob/v4.6.1/packages/eslint-plugin/docs/rules/no-unused-vars.md
8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?