(React ,Redux): Harmony => クソ実装1;

このクソエントリはクソ実装アドベントカレンダー1日めのクソエントリです。

私はTsuruっていうTwitter + Mastodon + Slackクライアントを作っており、というか復学してから露骨に進捗が死んでいるので終わっているんですが、終わっていようがいまいが太陽は沈むし月は昇っている。まだ…

Harmony of React and Redux

Tsuruの話をしましょう。

かつて動いていた図

見てわかる(わかるか?)通り、タイムラインを複数持っており、それぞれのタイムラインに独立したText Field(Form)を持っていることです。

独立したFormであり、状態を複数持っているということが問題を複雑にしています。Text Fieldの内容をアップロードしている間は編集できないように、投稿に失敗したら内容はそのままで失敗を通知するスタイルにする、投稿に成功したら内容は削除して次の投稿に備える、などもこなさなければなりません。

全てRedux上で持たせてしまえばよいのですが、私は(この頃は)すべてRedux上にデータを持たせることにうんざりしており、Class Componentでstateを持たせようという思考になります。ここで問題になるのが、「投稿に成功したら内容は削除して次の投稿に備える」という操作です。

Formに関するstateをRedux上に持たせていればRedux上で事が済むのですが、Local Stateに主となるテキストデータを持たせたために、「投稿に成功したら内容は削除して次の投稿に備える」が困難になってしまいました。Local Stateにテキストデータを持たせてしまった以上、どうやってRedux上からLocal Stateのテキストデータを消去すればいいのでしょうか?

class Form extends React.PureComponent {
constructor(props){
super(props);
this.state = {
text: "",
};
}

static initState = {
text: "",
}
    clear = () => this.setState(Form.initState);
    // 以下省略...
}

では、物語がredux-sagaに移動します。redux-sagaはReduxのmiddlewareであり、ひらたく言えばなんでもできます。
通常このredux-sagaではなんらかのAPIとの通信が行われるのが主ですが、分割されたreducer間で横断的にデータを処理する場合にも使われます。

class Form extends React.PureComponent {
constructor(props){
super(props);
this.state = {
text: "",
};
}

static initState = {
text: "",
}
    clear = () => this.setState(Form.initState);
    submit = () => this.props.requestSubmit({ // dispatch
text: this.state.text,
delegateClearForm: this.clear
});
    // 以下省略...
}

では悪用しました。actionのpayloadにデータだけではなく、そのコンポーネントのメソッドもぶちこんでしまうことで無理矢理解決します。そして、redux-sagaでは次のように利用します。

import * as api from '../Api/backend';
import { call } from 'redux-saga/effects';
export default function* requestUpdateStatus(action) {
try{
yield call(api.updateStatus, action.payload.text);
action.payload.delegateClearForm();
} catch (e) {
// API呼び出し失敗時はだるいので省略
}
}

便利ですね。Reduxの欠点「冗長」が緩和され、そのコンポーネント特有のstateはlocal stateとして自明に持たせることができるので便利です。便利なので今もこの手法を使いますが、この手法の最悪な点は「Fluxを使う意味がない」「これを使いまくると知らない場所からやってくる副作用の悪夢になる」「どこで何が起きたのかわかんなくなる」「段々意味不明になっていく」という点において最悪です。

そもそもこのような事になるのであればRedux上にstateを持たせてあげればよい話であり、つまるところ、設計の問題になってしまいます。設計ちゃんとしましょう。

まあ便利なものや手法は過剰に使いすぎると欠点が増幅されていき欠点に収束してしまうというのが世の常なので、やがて人々が増えていくと欠点がどんどん収束していき、死んでしまうでしょう。あるいは、ハーモニー…