下記で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にも同様の議論があった
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を参照して設定
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