Expressの公式ドキュメントを読んでみた
ちなみに、日本語版はこっち⇨ Express - Node.js Web アプリケーション・フレームワーク
僕の今いる会社はRailsでの開発がメインなのでバックエンドはほとんどRailsを使っている。
だが、最近はRailsは確かに便利だと思いつつも、Railsのなんでもよしなにやってくれるところがあまり好きではなくなっていってる。
Rails wayに載ってる限りは便利だが、そこから外れると一気にめんどくさくなるのも微妙。
そう思ってる時にExpressを使ってみたところ、ExpressはRailsと比べて本当にシンプルなので一気に好きになってしまった。
それに、これまでRailsが気を利かせていい感じにやってくれてたおかげであまり意識しなかったような基本的なところもExpressを使うことで学べたりするのも大きい。
なので、Expressの公式ドキュメントを読んでみた。
middleware
expressjs.com
RailsからExpress入って大きく違うのは、middlewareをどれだけ意識するかってところだと思う。
Railsだとこの辺りはそんなに意識することがなくて、基本的にはビジネスロジックに集中できるけど、Expressはこの辺りも全部自分で逐一設定しないといけない。
Railsだとcookieは簡単に使えるけど、Expressだとパッケージをインストールするところから始めないといけないんだよなあ。
ルーティング
expressjs.com
ルーティングはmiddlewareほどRailsと変わりはないが、ただ、逐一自分で設定しないといけないというところはRailsと違う。
ルーティングのつなぎこみは、なんとなくgrapeに似ているような気がしたけどどうなんだろう。
というか、grapeってまだ開発続いててビックリした。
Rails4時代のgemってイメージがあった。
React Routerの公式ドキュメントを読んでみた
まだそんなにガチで使ったことなかったからざっくり流し読みした程度。
reacttraining.com まずはこのPhilosophyページを読むとわかりやすいと思った。
以下雑感。
Redirect
reacttraining.com
こう言う風にコンポーネントを書くようにしてRedirectするのは、railsのredirect_to
とかに慣れてるとちょっと面食らうなと思った。
routhingのネスト
railsのresources
みたいな感じのこともできるんだと感動。
これうまく使えれば、railsみたいにコントローラーファイルを複数に分けることもできるよなあ。
すごく便利そう。
デバイス別のレイアウトの分け方
reacttraining.com
これもすごいなと思った。
ルーティングでここまでできるんだと感動。
media queryのところは
GitHub - d6u/react-container-query: Modular responsive component
この辺とかつかってやればよさそうだし。
最近やたら薄い記事しか書いてないな...
仕事で色々知見が貯まってきてはいるので、どこかのタイミングで書いておきたい。
Reduxの公式ドキュメントを読んでみた
読んでみたはいいけど、全然頭に入ってこねー。
正直、仕事でReduxを使ったことがない。
仕事でやったことあるのは、RailsのviewをReactで作るって感じで、stateもそんなに大きくないからHooksで十分だった。
個人開発でも大体Hooksで書いてしまう。
これから使う予定があるとしたら、個人開発で作ってるSPAの認証の際に、認証情報をReduxに入れるくらいだと思うんだけど、それだとあまりReduxの設計にこだわらなくていいんだよなあ。
useReducer
とReactのcontext
が出てきた今、そんなにReduxを使う機会は多くなっていないような気がする。
「Reduxは大規模開発では使ったほうがいい」という趣旨の記事を何度かみたことあるけど、まだそんな規模の開発をしたことないから、公式ドキュメントのAdvanced TutorialやRecipesに書かれている内容はピンとこなかった。
むしろ、JavaScript: Reduxが必要なとき/不要なとき(翻訳) に書いてあるような、Reduxを使わないでいいタイミングや逆に使うべきタイミングを知りたい。
この記事はHooks登場以前のものみたいだけど、Hooks登場以降のRedux使用の見分け方を知りたいな。
大規模開発以外にも色々な条件がありそうな気がする。
またReduxを実際に使うタイミングで読んでみることにしよう。
Reactの公式ドキュメント読んでみた その3 HOOKS編
今回はReactのHooksの公式ガイドを読んでみた。
Hooksはこれまで仕事などで使っていたので、割とわかっていると思っていたが、思いのほか知らないことが多かった。やっぱり公式を読んでおくのは大事。
ただ、まだパフォーマンスを気にするほどの画面は作ったことがないので、その辺は飛ばしている。
あと、まだ使ったことのない useMemo
とか useCallback
などは、また別の記事に使い心地について書くようにしたい。
前回のstateやpropsの取得
ja.reactjs.org
refを使って自分でやる必要があるのか。
refってフォームの入力値を取得するためにしか使ってこなかったけど、こういう使い方もあるのね。
DOMノードの位置とサイズの測定
ja.reactjs.org
こういうのもref使うのか。
思ったよりrefって活躍しそうだからちゃんと使えるようになっておこう。
どうでもいいけど、refってTypeScriptで書きにくい気がする。
useEffect
内で使用する関数の宣言場所
ja.reactjs.org
これ今やっている仕事でちょうどダメな例の方をやってしまっていた...
出社したら修正しておこう。
というか、基本的に、useEffect
内で使う関数は、もしその関数がstate
やprops
を使うならuseEffect
の中に書いておけって話か。
何でもかんでも内部に書くと見通しが悪くなってあまり好きじゃないんだけど、そっちのほうが安全そう。
単純に計算結果を返すだけの関数なら外部に書いても大丈夫みたいだけどね。
子コンポーネントのメモ化
これは少し感動した。
いつか使ってみたい。
計算量の大きいオブジェクトの遅延作成
まだそんなに計算量の大きいオブジェクトを作ったことはないけど、これもよさそうなテクニック。
setStateの初期値には関数も渡せるのね。
Reactの公式ドキュメント読んでみた その2ADVANCED GUIDES編
前回はReactの基本コンセプトを読んだので、今回は次のADVANCE GUIDESを読んでいこうと思う。
ただ、今回は前回ほどの量はなさそう。
理由としては、これどのタイミングで使うんだ...?ってものがあったり関数コンポーネントを使うようになってる現在ではあまり役に立たなそうなものがあったりしたから。
コード分割(code-splitting)
これは便利そう。要はlazy loadしたいのね。
業務でSPAを作ったことはまだないが、実際に作ることになったらよさそうだなあと思う。
Contextの使用
Contextってグローバルに値を読めるようになって怖いからなるべく使わないようにしてたんだけど、実際どのくらい使われるのか謎。
ja.reactjs.org
ここの冒頭にも書いてあるけど、必要な値を直接埋め込んでしまうから再利用性低くなるのはそうだと思う。
Context使うくらいならRedux使ったりしたほうがいいんじゃないだろうか。
blog.logrocket.com ここを読むと、Reduxとかを使うのはやりすぎな時に使う感じっぽい。
Error Boundary
ただ、Error Boundary
については、ComponentDidCatch
っていうライフサイクルメソッドを使わないといけないらしいんだけど、関数コンポーネントを使うのが主流となった今はこれは使えないよなあと思った。
blog.bitsrc.io
で、色々ググったところ、現時点ではError Boundaryを使うなら結局はクラスコンポーネントを使わないといけないっぽい?
この辺はまたおいおい調べよう。
今回はだいたいこんな感じ。
次はHooksについてのドキュメントを読もう。
Reactの公式ドキュメント読んでみた その1 MAIN CONCEPT編
最近はReactのドキュメントに目を通している。 以前にいきなり納期がタイトなReactの案件を振られて、四苦八苦しながらコード書いて以降、Reactについてわかった気になっていたが、改めてドキュメントを読むと色々と学びがあったのでメモしておく。
ある条件下でレンダリングさせない
これは知らなかった。
return
でnull
を返せばそのコンポーネントのレンダリングを阻止できるのね。
見せたくないだけなら、条件分岐の元になるフラグでdisplay: none
をスタイルに追加すればいいかなと思ってたけど、どっちがいいんだろう。
stackoverflowにこんな質問があったけど、CSSでやれば早いし、return null
でやればDOMは小さくなるよ、って感じなのかな。
そもそもそんなに気にしなくてもいいのかも。
map
で要素を繰り返し表示するときに key
にindex
を使わない
これまでは普通にkey
にindex
使ってた...。
ただ、前に書いたコードを見たら並び替えはないから特に問題はなさそう。
ここで紹介されているkey
にindex
を使ったサンプルを見ると確かにヤバそう。
本当は頭に行を追加したいはずなのに、末尾に追加されてしまってる。
codeburst.io
ここにはどういうものをkey
にすればいいかの指針が載っている。
フォームでは制御コンポーネント(controlled components
)を使う
制御コンポーネントってのはstate
でinput
の値を管理するようなもので、そうしないものが非制御コンポーネント(uncontrolled components
)。
ref
を使う場合は非制御コンポーネントになる。
僕はreactを使う案件にアサインされたはじめのほうでref
使えって言われたから盲目的にそうしていたけど、
ja.reactjs.org この記事の中で
ほとんどの場合では、フォームの実装には制御されたコンポーネントを使用することをお勧めしています。
と書いているし、state
を使うほうが公式のやり方なのか。
ただ、state
でやると入力値が変わるたびにstate
の更新が走ってそれはそれでめんどくさくないかと思ってたらこういう記事を見つけた。 この記事の結論はとてもわかりやすい。
goshakkk.name 次フォームを扱う時はこのやり方に倣おう。
Reactで画面を作る過程
この記事は全体的に最高。
特にコンポーネントの切り出しにUIイメージを使うとかstate
の決定の仕方とかとても参考になった。
まとめ
前に少し読んでclassで書かれてるじゃん...って思ってスルーしていたが、ちゃんと読んでみたらすごいためになる内容だった。
次は ADVANCED GUIDES とか HOOKSを読んでいきたい。
react + redux-thunk + typescriptでよくあるカウンターのサンプル
redux-thunkをreactとtypescriptで使ってみたかったので、よくある簡単なカウンターを作ってみた。
ただ、typescriptに慣れてなかったりそもそもreduxに触ったばっかりって感じで、表示のガワ部分を作ったあとのactionやreducerあたりは全部presentationalなコンポーネントの中に書いている。
いきなりファイルを分けすぎるとかえって把握しづらかったため。
index.tsx
import React from "react" import ReactDOM from "react-dom" import "./index.css" import * as serviceWorker from "./serviceWorker" import { Provider } from "react-redux" import thunk from "redux-thunk" import { createStore, applyMiddleware } from "redux" import Buttons, { reducer } from "./Buttons" let store = createStore(reducer, applyMiddleware(thunk)) ReactDOM.render( <Provider store={store}> <Buttons /> </Provider>, document.getElementById("root") ) serviceWorker.unregister()
Buttons.tsx(よくあるApp.tsxと同じ)
import * as React from "react" import { connect } from "react-redux" import { Dispatch, Reducer, ActionCreator } from "redux" import AddButton from "./AddButton" import CounterPanel from "./CounterPanel" import DecrementButton from "./DecrementButton" import IncrementButton from "./IncrementButton" import AsyncIncrementButton from "./AsyncIncrementButton" import { ThunkAction, ThunkDispatch } from "redux-thunk" interface CounterState { count: number } enum CounterActionType { ADD = "COUNT/ADD", INCREMENT = "COUNT/INCREMENT", DECREMENT = "COUNT/DECREMENT" } interface CounterAction { type: CounterActionType amount?: number } interface ButtonsProps { count?: number add?: (amount: number) => void increment?: () => void decrement?: () => void asyncIncrement?: () => void } const Buttons: React.FC<ButtonsProps> = ({ count = 0, add = () => {}, increment = () => {}, decrement = () => {}, asyncIncrement = () => {} }) => { return ( <div> <CounterPanel count={count} /> <IncrementButton onClick={increment} /> <DecrementButton onClick={decrement} /> <AddButton onClick={() => add(10)} /> <AsyncIncrementButton onClick={asyncIncrement} /> </div> ) } // action const add = (amount: number): CounterAction => ({ amount, type: CounterActionType.ADD }) const increment = (): CounterAction => ({ type: CounterActionType.INCREMENT }) const decrement = (): CounterAction => ({ type: CounterActionType.DECREMENT }) const asyncIncrement: ActionCreator< ThunkAction<void, CounterActionType, null, CounterAction> > = () => { return (dispatch: Dispatch) => { setTimeout(() => { dispatch({ type: CounterActionType.INCREMENT }) }, 3000) } } // reducer export const reducer: Reducer<CounterState, CounterAction> = ( state: CounterState = { count: 0 }, action: CounterAction ): CounterState => { switch (action.type) { case CounterActionType.ADD: return { ...state, count: state.count + (action.amount || 0) } case CounterActionType.INCREMENT: return { ...state, count: state.count + 1 } case CounterActionType.DECREMENT: return { ...state, count: state.count - 1 } default: const _: never = action.type return state } } interface StateProps { count: number } interface DispatchProps { add: (amount: number) => void increment: () => void decrement: () => void } const mapStateToProps = (state: CounterState): StateProps => ({ count: state.count }) const mapDispatchToProps = ( dispatch: ThunkDispatch<any, any, CounterAction> ) => ({ add: (amount: number) => dispatch(add(amount)), increment: () => dispatch(increment()), decrement: () => dispatch(decrement()), asyncIncrement: () => dispatch(asyncIncrement()) }) export default connect( mapStateToProps, mapDispatchToProps )(Buttons)
typescriptの型指定はまだ全然慣れない。
前の会社ではC++とかJavaとか触ってたけど、今の会社でrubyを触り始めて型についてすべて忘れてしまった。
このサンプルを作ってる中で気になったんだけど、reduxってどの程度hooksで置き換えられるんだろう。
100%は無理にしても割と置き換えられるんじゃないかなあって気がしている。
最近は
この本が良かった。
萌え系って苦手だから表紙でちょっと避けてたけど、中見たら萌え要素全く無かったし、内容もかなりわかりやすく書かれていたしですごくよかった。
そろそろサンプル以上のものを作るようにしたい。