babelからtypescriptへ。あとreact hookも試す。

下記でbabel使った環境を作りflowtype入れようと思ったらflowserverとの相性が悪い様で動作が安定しない
久々にReact触ったら色々変わっていたので改めて環境構築
https://kara100.com/javascript/react16-babel7-webpack4/

flowserverが止まったりファイルがロックされてnpm installが失敗したり。
flowを使うのをあきらめてtypescriptに移行してみる。

typescriptは使ったことが無かったので色々と調べる。そして分かったことはtypescript使うとbabelはいらないorz
直すのも面倒なので作り直す。環境作りに時間かけすぎな気がする。。。

github
https://github.com/umema4/react16_webpack4_typescript

初期設定

publicディレクトリに起点となるindex.htmlの作成

npm init
mkdir public src
code public/index.html

typescriptのインストール

npm i --save-dev typescript ts-loader
npx tsc --init

とりあえず下記を変更

{
-  "module": "commonjs",
+  "module": "es2015",
+  "lib": [
+    "es2020",
+    "dom"
+  ],
+  "jsx": "react",
+  "sourceMap": true,
+  "moduleResolution": "node",
+  "allowSyntheticDefaultImports": true,
}

webpackの設定

npm install --save-dev webpack@latest webpack-cli@latest webpack-dev-server@latest style-loader@latest
css-loader@latest postcss-loader@latest cssnano

webpack.config.jsの設定

entryをtsxのファイルに変更

  entry: './src/index.tsx',

babel-loaderで書いていたところをts-loaderに置き換える

  {
    test: /\.tsx?$/,
    use: 'ts-loader'
  }

resolveにts用ファイルの追加

  resolve: {
    extensions: ['.ts', '.tsx', '.js'],
  },

reactのインストール

npm i --save react react-dom @types/react @types/react-dom

以前と同じコードをtsxで用意してnpm run startを実行するとエラーが発生。

TS2307: Cannot find module './App.css'.

css-loaderがうまく動いていない。
TypeScriptはCSSのインポートとしての解釈はしてくれない。
TypeScriptdでもCSS modulesとして扱いたいので対応を検討。

単純に対応するのであればimportをrequireに書き換えれば動作はする。

stack overflowにも同様の議論があった

https://stackoverflow.com/questions/41336858/how-to-import-css-modules-with-typescript-react-and-webpack

typescriptではrequireはあまり使われないらしい。

typings-for-css-modules-loaderはメンテされていないのでちょっと避けたい。

手っ取り早いのは型定義してしまう方法のようなので。
src/types/global.d.tsを作成し下記を設定することで問題を解決。

declare module '*.module.css';

eslintとprettier

関連モジュールのインストール

npm i --save-dev prettier eslint-config-prettier eslint-plugin-prettier pretty-quick

airbnbのtypescript版があったのでこちらを導入
https://github.com/iamturns/eslint-config-airbnb-typescript

npm install eslint-config-airbnb-typescript \
            eslint-plugin-import@^2.20.1 \
            eslint-plugin-jsx-a11y@^6.2.3 \
            eslint-plugin-react@^7.19.0 \
            eslint-plugin-react-hooks@^2.5.0 \
            @typescript-eslint/eslint-plugin@^2.24.0 \
            --save-dev

typescript+eslintの設定は下記のREADMEを参照して設定

https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/README.md

npm i --save-dev eslint @typescript-eslint/parser

eslintrcを更新

  "extends": [
    "airbnb-typescript",
    "airbnb/hooks",
    "prettier",
    "prettier/@typescript-eslint",
    "prettier/react"
  ],
  "parser": "@typescript-eslint/parser",

stylelintとprettier

npm install --save-dev stylelint stylelint-config-standard

前回はstylelint-config-recommendedを入れていたけど今回はstandardに変更。
なんだかstylelint-config-recommended入れると挙動が怪しい。

stylelintでもprettierが使えるようだ

npm install --save-dev stylelint-prettier stylelint-config-prettier

stylelintrcにextendsを追加

  "extends": [
    "stylelint-config-standard",
+   "stylelint-prettier/recommended"
  ],

複数のlintだけをまとめてかけたいと思ったらnpm-run-allというパッケージがあった
これでlintをまとめてかけられるようになった。

npm install --save-dev npm-run-all

こうしておけばnpm run lintでlint:*をまとめて実行してくれる

    "lint": "run-p lint:*",
    "lint:eslint": "eslint src --ext tsx",
    "lint:tsc": "tsc --noEmit",
    "lint:style": "stylelint  ./src",

あとはlint-stagedを設定

npm i --save-dev husky lint-staged

これで諸々基本的な設定が完了。

ReactのDocsを読み返して

以前と変わっているところとか勉強不足だったところを確認するためDocsを読み返す

bindの扱い

constructorにbindを書きたくないのでbabelの時はplugin-proposal-class-propertiesを入れていた
typescriptでは特に設定しなくても下記の形式で問題なかく動いた

class Button extends Component {
  handleClick = () => {
    console.log('test');
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

フラグメント

複数要素を返したい場合に余計なnodeをつけなくてよくなる
下記のように書けるらしい。これはいい感じ。

class Columns extends React.Component {
  render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    );
  }
}

React.lazy

componentの遅延ロード。

react routerと相性が良いのは分かったがコード分割する必要があるのでwebpackの設定をかえないといけなそう。
必要になったら設定を見直す。今は放置でいいや。

Context

子Componetに対してpropのバケツリレーが不要になる。すべー便利そう。

componentDidCatch

エラー取るために便利そう。containerあたりに仕込んでおくのがよいのかな。

Portal

親Component外にcomponentを書く仕組み。popupとかmodalで使えるらしい。
モーダルとかはUIライブラリに任せちゃう気がするので自分で使う場面は少ないかも。

react-hooks

自分が触っていたときとの一番の違いはこいつだろう。
自分が開発していたときはRedux最盛期。開発からは離れてからはreact-hooksが登場しゲームチェンジが起こって
reduxを駆逐し始めていると聞く。

hook概要

  • useStateで関数の中でstateが使えるようになる
  • useEffectで関数の中でDOMの変更後の副作用を追える
  • ループや条件分岐、ネストした関数の中で使ってはいけない
  • 関数コンポーネントの内部でのみ使うことができる
  • useXXXというフックの処理だけを行うカスタムフックという関数を作ることはOK

条件分岐で使えない理由

どの useState の呼び出しがどの state に対応するのかはフックが呼ばれる順番に依存している。
renderごとに同じ順番で呼ばれることを期待しているのでその順番が狂わないように条件分岐などで呼び出し順番が変わってはいけない。

useStateは関数型で更新できる

setState((prev) => {
  return prev + 1;
})

とかで更新かけられる

prevProps, prevState

useEffectの第2引数の配列で値の変更があったときのみuseEffectが呼び出される。

shouldComponentUpdate

公式のQAにあった
https://ja.reactjs.org/docs/hooks-faq.html#how-do-i-implement-shouldcomponentupdate

React.memoを使うらしい

reduxが置き換えらえる理由

useReducerが用意されている。ローカルstateはこれで管理すればよいはず。
グローバルステートはどう使うべきか->Contextで置き換え可能。

React-ReduxでRedux Hooksが使えるようになっている。
Hooksだけでも結局Providerとか自分で用意してstore作るのであれば利用者が多いモジュール使ったほうが
事故が少ない気がする。

グローバルなデータを扱うだけであればreactnについての記事がちょこちょこあった
reduxだとオーバースペックな気もするし

ディレクトリ構成はどうするのか

今までは

containers
components
actions
reducer

という構成だった

hooks使う場合はどうしておくのがきれいなのだろう

公式の見解
https://ja.reactjs.org/docs/faq-structure.html

やべえ。5分以上かけるなってい書いてあるwww

react hooks directory structure

とかでググった感じこんな感じにしておくのがよさそうか

components
pages or context
hooks
reducers

返信を残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

two × four =