Redux 核心概念
R核心概念有三个:
actions
store
reducers
简单地,Actions就是事件。Actions传递来自这个应用(接口,内部事件比如API和表单提交)的数据给store。store只来自Actions的信息。内部Actions就是简单的具有type(通常是常量)的JavaScript对象,这个对象描述了action的类型以及传递给store的信息。
{ type: LOGIN_FORM_SUBMIT, payload: {username: 'alex', password: '123456'} }
Actions通过action器创建,它们仅仅是是返回action的。
function authUser(form) { return { type: LOGIN_FORM_SUBMIT, payload: form } }
要在应用中的任何地方actions很容易,使用dispatch。
dispatch(authUser(form));
在式JavaScript中reducer基于数组reduce,接收回调(reducer)让你从多个值中获得单个值,整数和,或者一系列值的累积。在R中,reducer就是获得这个应用的当前状态和事件然后返回新状态的。理解reducer是怎样工作的至关重要,因为它们完成大部分工作。这是非常简单的reducer,通过当前state和action作为参数,再返回下state:
function handleAuth(state, action) { return _.assign({}, state, { auth: action.payload }); }
对于更多复杂的项目,使用R提供的combineReducers()实例是必要的(推荐)。它把个应用中所有的reducer结合在一起成为单个索引reducer。每reducer负责它自己那部分应用的状态,这个状态参数和其他reducer的不一样。combineReducers()实例使结构更容易维护。
如果对象(state)只改变一些值,R就创建新的对象,那些没有改变的值将会指向旧的对象而且新的值将会被创建。这对是极好的。为了让它更有效率你可以 Immutable.js
const rootReducer = combineReducers({ handleAuth: handleAuth, editProfile: editProfile, changePassword: changePassword });
Store对象保存应用的状态并提供一些帮助来存取状态,分发状态以及监听。全部state由store来表示。任何action通过reducer返回新的状态对象。这就使得R非常简单以及可预测。
import { createStore } from 'r'; let store = createStore(rootReducer); let authInfo = {username: 'alex', password: '123456'}; store.dispatch(authUser(authInfo));
R 核心概念示例
R 本身很简单,当使用普通对象来描述应用的 state 时。
例如,todo 应用的 state 可能长这样:
{ todos: [{ text: 'Eat food', completed: true }, { text: 'Exercise', completed: false }], visibilityFilter: 'SHOW_COMPLETED' }
这个对象就像 “Model”,区别是它并没有 setter(器)。因此其它的不能随意它,造成难以复现的 bug。
要想更新 state 中的数据,你需要发起 action。Action 就是普通 JavaScript 对象(注意到没,这儿没有任何魔法?)用来描述发生了什么。下面是一些 action 的示例:
{ type: 'ADD_TODO', text: 'Go to swimming pool' } { type: 'TOGGLE_TODO', index: 1 } { type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }
强制使用 action 来描述所有变化带来的好处是可以清晰地知道应用中到底发生了什么。如果一些东西改变了,就可以知道为什么变。action 就像是描述发生了什么的指示器。最终,为了把 action 和 state 串起来,开发一些,这就是 reducer。再次地,没有任何魔法,reducer 只是接收 state 和 action,并返回新的 state 的。 对于大的应用来说,不大可能仅仅只写这样的,所以我们编写很多小来分别管理 state 的一部分:
function visibilityFilter(state = 'SHOW_ALL', action) { if (action.type === 'SET_VISIBILITY_FILTER') { return action.filter } else { return state } } function todos(state = [], action) { switch (action.type) { case 'ADD_TODO': return state.concat([{ text: action.text, completed: false }]) case 'TOGGLE_TODO': return state.map((todo, index) => action.index === index ? { text: todo.text, completed: !todo.completed } : todo ) default: return state } }
再开发 reducer 这两个 reducer,进而来管理整个应用的 state:
function todoApp(state = {}, action) { return { todos: todos(state.todos, action), visibilityFilter: visibilityFilter(state.visibilityFilter, action) } }
这差不多就是 R 思想的全部。注意到没我们还没有使用任何 R 的 API。R 里有一些工具来简化这种模式,但是主要的想法是如何根据这些 action 对象来更新 state,而且 90% 的都是纯 JavaScript,没用 R、R API 和其它魔法。