読者です 読者をやめる 読者になる 読者になる

へっぽこびんぼう野郎のnewbie日記

けろけーろ(´・ω・`)!

reduxよくわかんなかったのでPythonでredux実装した

Redux JavaScript Python
class createStore:
    """ほんとはシングルトンにしないといけないけどわかりづらくなるのでやめた

    関数にした場合は、Pythonだと "JavaScriptでは全然考えられてないローカルスコープ" で大変そうなのでクラスにした"""
    def __init__(self, reducer):
        self._state = None
        self._listeners = []
        self._reducer = reducer

    def subscribe(self, listener):
        self._listeners.append(listener)

        def unsubscribe(listener):
            self._listeners.remove(listener)

        return lambda: unsubscribe(listener)

    def dispatch(self, action):
        # Python特有の書き方
        if not self._state:
            self._state = self._reducer(action)
        else:
            self._state = self._reducer(action, self._state)
        # 特有の書き方ここまで
        for listener in self._listeners:
            listener()

    def getState(self):
        return self._state


# 実装ここまで(`・ω・´)
# あとは使い方だけ


# (state=0, action)という書き方はPythonではエラー
def counter(action, state=0):
    """いわゆるreducer。実際はこれをいっぱい書いてcombineReducersとかでまとめる"""

    # Pythonにはswitch文はない
    if action.type == "INCREMENT":
        return state + 1
    elif action.type == "DECREMENT":
        return state - 1
    else:
        return state


store = createStore(counter)


def printListener():
    """render()とかって名付けてReactDOM.render()呼べば幸せになれるリスナー"""
    print(store.getState())


store.subscribe(printListener)


# JSのObjectに相当するものをつくるだけ
class Action:
    def __init__(self, type, **kwargs):
        self.type = type
        for k, v in kwargs.items():
            setattr(self, k, v)

print("がんばるぞい!")
store.dispatch(Action(type="INCREMENT"))
store.dispatch(Action(type="INCREMENT"))
store.dispatch(Action(type="DECREMENT"))
store.dispatch(Action(type="DECREMENT"))
store.dispatch(Action(type="DECREMENT"))


# おまけ
def increment():
    """Action Creator"""
    return Action(type="INCREMENT")


store.dispatch(increment())
$ python3 redux.py
がんばるぞい!
1
2
1
0
-1
0

蛇足な解説

reduxって何するものなの?

状態を一元管理したい!!!!!!!!!
いろんなところに、いろんな状態が散らばってるの最悪だ!!!!!

だからなんとかしよう
ってやつ

reactとはどう関係するの?

作る動機がreact関連のFluxだっただけで、reactは関係ない

reactと連携するには?

react-redux とかいうのを使う
それはこのソースには入ってないので注意!

react-reduxっていっても、Providerと、connect関数しかないのでかんたん……かと思いきやよくわかんなかった
……(´・ω・`)

reduxのしくみ
  • storeというところでstateを一元管理
  • stateを変えるには、Actionを実行するしかない
  • Actionとは、stateを変更するために何を起こすのかを書いたJSのPlain Object(Plain Objectについて知らない人はググってください。lodashの中のソースがおすすめです)
  • Actionと、現在のstateから、どうstateを変更するのか(要はActionに書いたものの具体的な中身)を決めるのがReducer
store.dispatch(アクション)

こう書いてstore.dispatchすると、reducerに処理が委譲されて、storeの中のstateが変更される。

  • combineReducers()すると、reducerの関数名がstateのキーになる
  • storeに入ってるstateを取るにはstore.getState()すればいい
  • store.subscribe(リスナー)で、「stateが変更されたときに(詳しく言うとstore.dispatch関数が呼ばれたときに)呼びたい関数」を登録する

あとはオマケ

react-redux
  • store.subscribe(リスナー)の部分をconnect()という関数で隠蔽した。変更されたstateをpropsに渡してreactのレンダーまでしてくれるだけ(たぶん)

コメント

reduxはわかったけど、なんかまだもやもやってしてるので、react-reduxとか詳しい人や、プロジェクト走らせてる人から話がききたいです