• ..

JavaScript

    Redux Devtool を使う

    Redux を使って状態を管理している Web サービスなどで「状態の流れ」を調査しやすくしてくれるツールです。僕的には開発時には必須な感じで使っています。

    Chrome 拡張を入れる

    Chrome 依存になってしまいますが、 Chrome 拡張で入れてしまうのが1番てっとり早いかなと思います。この辺は開発時に1番使うので問題ないかなと考えてます。

    Redux DevTools - Google Chrome

    入れたあとはwindow__REDUX_DEVTOOLS_EXTENSION__というフック関数が増えているはずです。適当なページを開いて Devtool のコンソールを開いて確認できます。

    Redux の createStore に REDUX_DEVTOOLS_EXTENSION を渡す

    Redux のcreateStoreの最後の引数にはenchancerという関数が渡せることになっています。これはzzz(yyy(xxx(...)))というような順番に適応する関数の集まりみたいなやつです。(compose(zzz, yyy, zzz)()と書かれていたりもする)

    ここに__REDUX_DEVTOOLS_EXTENSION__を渡します。今回はこれだけで1つなのでそのまま実行すればいいです。

    createStore(
      reducer,
      window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(),
    );

    TypeScript と一緒に

    そのままだと型警告が来ると思うのでこんな感じでwindowを拡張するといいです。

    declare namespace window {
      export const __REDUX_DEVTOOLS_EXTENSION__: Function | undefined;
    }

    react-redux の connect の Generic Types

    react-reduxconnectメソッドは4つの Generic Type を受け取れます。例えばconnectを以下のように使った場合、

    mapStateToProps だけの場合

    connect(state => state)(class extends React.Component<{foo: string}> {/* ... */})

    d.tsに書かれているこの型が適用されます。

    <
      TStateProps = {},
      no_dispatch = {},
      TOwnProps = {},
      State = {}
    >(
      mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>
    ): InferableComponentEnhancerWithProps<TStateProps & DispatchProp, TOwnProps>;
    1. TStatePropsこれは Redux の State からコンポーネントへ props として渡す props の型。つまりstate => stateのように書いた場合 Redux の State と同じものになります。
    2. no_dispatch上記のは mapDispatchToPropsが無いので{}を渡します。
    3. TOwnPropsはラップされるコンポーネントの props を渡します。
    4. Stateは Redux の State そのままです。

    例えば、上記の使い方で State が{hoge: number}であれば、

    connect<State, {}, {foo: string}, State>(state => state)(
      class extends React.Component<{foo: string}> {/* ... */}
    );

    となります。

    mapDispatchToProps と一緒の場合

    上記のno_dispatchTDispatchPropsに変わりました。これはTStatePropsのようにこのconnect関数の中のmapDispatchToPropsの戻り値の型を指定します。

    <
      TStateProps = {},
      TDispatchProps = {},
      TOwnProps = {},
      State = {}
    >(
      mapStateToProps: MapStateToPropsParam<TStateProps, TOwnProps, State>,
      mapDispatchToProps: MapDispatchToPropsNonObject<TDispatchProps, TOwnProps>
    ): InferableComponentEnhancerWithProps<TStateProps & TDispatchProps, TOwnProps>;

    例えば以下のようなprops.increment関数があるコンポーネントがあります。そしてそれはconnectの第二引数であるmapDispatchToPropsで定義している関数である場合このようになります。
    connectからコンポーネントに渡すprops型もReact.Componentに追加する必要があります。

    connect<State, {increment(): void}, {foo: string}, State>(
      state => state,
      dispatch => {
        return {
          increment() {/* ... */}
        }
      })
    (
      class extends React.Component<{foo: string} & {increment(): void}> {/* ... */}
    );