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

# はじめに

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';`する必要がないということです。
`React`を`import`しないようにすれば、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`の中身を見てみます。

```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`使われてないわけないだろｗ

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

## 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`を消しましょう。

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

```

めでたしめでたし。



## 3. 補足：JSXとは？

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

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


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

JSXの記法だと、

```tsx:
<Button type="submit">
  Click!
</Button>
```

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

```js:
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