LoginSignup
14
11

More than 3 years have passed since last update.

React-ReduxだけどReducerもActionも書かず、Dispatchすら使わず、データも何となく受け取れるようにする方法

Posted at

React-ReduxだけどReducerもActionも書かず、Dispatchすら使わず、データも何となく受け取れるようにする方法

前回
Reduxがあまりにも面倒なので、何もかも隠蔽しつつ、その力を引き出すことにした

とにかく面倒くさいFlux

 React上での状態管理は、ことごとくがFluxの考え方を用いて作られています。

 Actionのコマンドを定義してDispatchで送信し、Reducerで処理してStoreに書き込み、ViewがStoreの更新を察知して処理を行うという流れです。これらの処理の厄介なところは、全部が全部、記述箇所がバラバラになってしまうということです。

 とにかく何もかも面倒くさいので、この地獄から抜け出す方法を探しました。結果として、上記に書いたようなことを一切書かず、簡単にStoreデータを操作する方法にたどり着きました。

 環境設定と必要なパッケージ

今回のサンプルプログラムを動かすにはReact+TypeScript環境を用意してください。
また、以下のパッケージをインストールする必要があります。

npm -D i @jswf/redux-module

サンプルプログラム

 HooksのFunctionコンポーネントと、Classコンポーネントでの利用法を同時に載せているので、プログラムが少々長くなっています。
 中でやっているのはinputの内容をコンポーネント間で共有するというものです。
 もしこれをやるためだけにReduxの書式を真面目に書いたら、確実に無駄地獄へ落ちることが出来るでしょう。

 コンポーネント間のデータ共有にはReduxModuleというクラスを継承して利用します。
 クラスを作ると、クラスごとに一つStore領域が割り当てられます。
 そのため同じクラスを使用する限り、同じデータを参照することが出来ます。
 また、読み書きの受付も全てこのReduxModule継承クラスが担当するので、処理をあちこちに書く必要はありません

Microsoft Edge 2019-09-06 23-01-19.gif

https://github.com/JavaScript-WindowFramework/redux-module-sample

index.tsx
import React, { Component } from "react";
import * as ReactDOM from "react-dom";
import { createStore } from "redux";
import { Provider } from "react-redux";
import {
  ModuleReducer,
  useModule,
  ReduxModule,
  mapModule,
  mapConnect
} from "@jswf/redux-module";

/**
 *データ構造の定義(TypeScript使用時)
 *
 * @export
 * @interface TestState
 */
export interface TestState {
  msg: string;
}
/**
 *Storeアクセス用クラス
 *(クラスごとに自動的にStoreに領域を確保する)
 * @export
 * @class TestModule
 * @extends {ReduxModule<TestState>}
 */
export class TestModule extends ReduxModule<TestState> {
  //ここに初期値を設定可能
  protected static defaultState: TestState = {
    msg: "初期値"
  };
  //以下のようなアクセス用のメソッドは、必ずしも作る必要は無い
  //getStateとsetStateはpublicなので、外から直接書き換えてしまってもOK
  public getMessage() {
    return this.getState("msg")!;
  }
  public setMessage(msg: string) {
    this.setState({ msg });
  }
}

/**
 *Hooks用サンプル
 *
 * @returns
 */
function HooksApp() {
  //モジュールのインスタンスを受け取る
  //useModuleの使用可能場所の制限は他のhookと同じ
  const testModule = useModule(TestModule);
  //以下のようにPrefixを付けると、同じクラスが違う領域を持つことも出来る
  //const testModule = useModule(TestModule,"Prefix");
  return (
    <>
      <div>FunctionComponent</div>
      <input
        value={testModule.getMessage()}
        onChange={e => testModule.setMessage(e.target.value)}
      />
      <hr />
    </>
  );
}

/**
 *Class用サンプル
 *
 * @class _ClassApp
 * @extends {Component}
 */
class _ClassApp extends Component {
  render() {
    //モジュールのインスタンスを受け取る
    //Hooksと名前と引数が微妙に違うので注意
    const testModule = mapModule(this.props, TestModule);
    return (
      <>
        <div>ClassComponent</div>
        <input
          value={testModule.getMessage()}
          onChange={e => testModule.setMessage(e.target.value)}
        />
        <hr />
      </>
    );
  }
}
//クラスコンポーネントを利用する場合は以下の方法でマッピングする
//ここで宣言したモジュール以外はクラスで使用できない
//モジュールは配列で複数指定も可能
const ClassApp = mapConnect(_ClassApp, TestModule);

//Reduxに専用のReducerを関連付ける
//他のReducerと併用することも可能
const store = createStore(ModuleReducer);
ReactDOM.render(
  <Provider store={store}>
    <HooksApp />
    <ClassApp />
  </Provider>,
  document.getElementById("root") as HTMLElement
);

 必要なことのまとめ

1 ModuleReducerをReduxのStoreに関連付ける
2 ReduxModuleを継承したデータクラスを作成する
3 Classコンポーネントを使う場合はmapConnectで使用するデータクラスを関連付ける
4 useModule/mapModuleでデータクラスを呼び出す
5 setState/getStateでデータの読み書きを行う

一応解説しておく付加機能

 蛇足になるので最小限にとどめますが、データクラスは外部参照機能も付いています。
 別のデータクラスの機能が必要な場合はincludesに利用するモジュールを指定しておけば、getModuleで対象のクラスを呼び出すことが出来ます。

export class OtherModule extends ReduxModule {
  static includes = [TestModule]
  public getMessage() {
    return this.getModule(TestModule).getState("msg")!;
  }
  public setMessage(msg: string) {
    this.getModule(TestModule).setState({ msg });
  }
}

まとめ

 とにかく状態管理が楽になりました。これを使うことによって、コンポーネント間の手続きの大部分が省略可能となります。コンポーネント間のデータ共有にReduxを使いたいけれど、Flux的な書き方が嫌だと考えているのならぜひ使ってみてください。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11