Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions ja/Redux/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Redux

> この文章は[Redux][] [3.5.2](https://github.com/reactjs/redux/releases/tag/v3.5.2 "3.5.2")を元に書かれています。

[Redux][]はJavaScriptアプリケーションのStateを管理するライブラリで、
[React](https://github.com/facebook/react "React")などと組み合わせアプリケーションを作成するために利用されています。

Reduxは[Flux](https://facebook.github.io/flux/ "Flux")アーキテクチャに類似する仕組みであるため、事前にFluxについて学習していると良いです。

Reduxには[Three Principles](http://redux.js.org/docs/introduction/ThreePrinciples.html "Three Principles | Redux")(以下、三原則)と呼ばれる3つの制約の上で成立しています。

- Single source of truth
- アプリケーション全体のStateは一つのStateツリーとして保存される
- State is read-only
- StateはActionを経由しないと書き換えることができない
- Changes are made with pure functions
- Actionを受け取りStateを書き換えるReducerと呼ばれるpure functionを作る

この三原則についての詳細はドキュメントなどを参照してください。

- [Read Me | Redux](http://redux.js.org/)
- [Getting Started with Redux - Course by @dan_abramov @eggheadio](https://egghead.io/series/getting-started-with-redux)

Reduxの使い方についてはここでは解説しませんが、Reduxの拡張である _Middleware_ も、この三原則に基づいた仕組みとなっています。

_Middleware_ という名前からも分かるように、[connect](../connect/README.md)の仕組みと類似点があります。
[connect](../connect/README.md)の違いを意識しながら、Reduxの _Middleware_ の仕組みを見ていきましょう。

## どう書ける?

3行でReduxの仕組みを書くと以下のようになります。
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3行解説が上手く行ってない気がする。Storeについては忘れるというか、Storeの定義がむずかしい
4行になるのかもなー


- 操作を表現するオブジェクトをActionと呼ぶ - 一般にコマンドパターンのコマンドと同様のもの
- Actionを受け取りStateを書き換える関数を _Reducer_ と呼ぶ - ReducerはStoreに事前に登録する
- ActionをDispatch(`store.dispatch(action)`)することで、ActionをReducerへ通知する

Reduxの例として次のようなコードを見てみます。

[import, redux-example.js](../../src/Redux/redux-example.js)

1. `logger`と`crashReporter`のmiddlewareを適応した`createStore`関数を作る
2. Reducerを登録したStoreを作成
3. (Storeの変更をする)Actionをdispatch
4. Actionを受け取り新しいStateを返すReducer関数
5. Stateが変更されたら呼ばれる

というような流れで動作します。

上記の処理のうち、 3から4の間が _Middleware_ が処理する場所となっています。

`dispatch(action)` -> (_Middleware_ の処理) -> reducerにより新しいStateの作成 -> (Stateが変わったら) -> `subscribe`で登録したコールバックを呼ぶ

次は`applyMiddleware`がどのように _Middleware_ を登録しているのかを見ていきましょう。

## どういう仕組み?

- 高階関数をapplyしている
- http://rackt.github.io/redux/docs/advanced/Middleware.html
- その機構のコードへのリンク
- その仕組みやプラグインについてドキュメントへのリンク

## 実装してみよう

- [ ] TODO
- [ ] DispatcherベースのMiddleware

## どういう事に向いてる?
Copy link

@kuy kuy May 16, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reactコンポーネントでやりたくないサービス的な機能
他のプロジェクトでも使いまわせるのも特徴
だたし、Stateが必要な場合はReducerも一緒に提供する必要がある。
それすら面倒であればStore Enhancerを導入することもできる。
例えばredux-devtools-instrumentはStore Enhancerを提供することで、アプリ自体のStoreとは別のStoreを持っている。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ReduxのProsであって、ReduxのMiddlewareの仕組みにおけるProsとはまた異なる気がします。


- [ ] TODO
- アスペクト的に前後に処理を挟むことができる
- ログへの利用
- 値自体は直接操作するわけではないが、受取るデータは変換できる

## どういう事に向いていない?

- [ ] TODO
- 変換の仕組み上、書き換え等を行うプラグインを扱いにくい

## この仕組みを使ってるもの

- Connectに似ている
- _Middleware_もStateそのものを直接書き換える事はできません。
- この部分が類似の仕組みを持つ[connect](../connect/README.md)との違いになっています。



[Redux]: https://github.com/reactjs/redux "reactjs/redux: Predictable state container for JavaScript apps"
File renamed without changes.
File renamed without changes.
File renamed without changes.
29 changes: 29 additions & 0 deletions src/Redux/redux-example.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {createStore, applyMiddleware} from "redux";
import logger from "./logger";
import crashReporter from "./timestamp";
// 4. Actionを受け取り新しいStateを返すReducer関数
const reducer = (state = {}, action) => {
switch (action.type) {
case "AddTodo":
return Object.assign({}, state, {title: action.title});
default:
return state;
}
};
// 1. `logger`と`crashReporter`のmiddlewareを適応した`createStore`関数を作る
const createStoreWithMiddleware = applyMiddleware(logger, crashReporter)(createStore);

// 2. Reducerを登録したStoreを作成
const store = createStoreWithMiddleware(reducer);

store.subscribe(() => {
// 5. Stateが変更されたら呼ばれる
const state = store.getState();
// 現在のStateを取得
console.log(state);
});
// 3. Storeの変更をするActionをdispatch
store.dispatch({
type: "AddTodo",
title: "Todo title"
});
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// LICENSE : MIT
"use strict";
const assert = require("power-assert");
import applyMiddleware from "../../src/redux/apply-middleware";
import Dispatcher from "../../src/redux/Dispatcher";
import timestamp from "../../src/redux/timestamp";
import createLogger from "../../src/redux/logger";
import applyMiddleware from "../../src/Redux/apply-middleware";
import Dispatcher from "../../src/Redux/Dispatcher";
import timestamp from "../../src/Redux/timestamp";
import createLogger from "../../src/Redux/logger";
describe("middleware", function () {
it("could apply logger middleware", function () {
const dispatcher = new Dispatcher();
Expand Down
2 changes: 1 addition & 1 deletion test/redux/logger-test.js → test/Redux/logger-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"use strict";
const assert = require("power-assert");
import {createStore, applyMiddleware} from "redux";
import createLogger from "../../src/redux/logger";
import createLogger from "../../src/Redux/logger";
const initialState = {};
const reducer = (state = initialState, action) => state;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"use strict";
const assert = require("power-assert");
import {createStore, applyMiddleware} from "redux";
import timestamp from "../../src/redux/timestamp";
import timestamp from "../../src/Redux/timestamp";
const initialState = {};
const reducer = (state = initialState, action) => {
switch (action.type) {
Expand Down
5 changes: 4 additions & 1 deletion test/prh.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,7 @@ rules:
- 文字列オブジェクト

- expected: わけでは
patterns: 訳では
patterns: 訳では

- expected: 三原則
patterns: 3原則