Redux
主要分爲三個部分 Action
、Reducer
、及 Store
javascript
原理:java
view
直接觸發dispatch
;react
將action
發送到reducer
中後,根節點上會更新 state
,改變全局view
。redux
本案例以一個提到TODOLIST爲案例。app
在 Redux
中,action
主要用來傳遞操做 State
的信息,只是一種命令,並無實際改變state
。ide
咱們約定,action
內必須使用一個字符串類型的 type
字段來表示將要執行的動做。type
屬性是必要的,除了 type
字段外,action
對象的結構徹底取決於你,建議儘量簡單。type
通常用來表達處理 state
數據的方式。函數
好比添加todo
的action
:ui
const ADD_TODO = 'ADD_TODO' { type: ADD_TODO, text: 'Build my first Redux app' }
這個動做須要改變哪些屬性就傳遞這些屬性。spa
若是有多個數據是一樣的動做,那麼咱們就須要一個通用的函數來傳遞數據。在 Redux
中的 action
建立函數只是簡單的返回一個 action
:code
//actions export const ADD_TODO = 'ADD_TODO' export function addTodo(text) { return { type: ADD_TODO, text } }
或者
//actions export const ADD_TODO = 'ADD_TODO' export const addTodo = (text) => { return { type: ADD_TODO, text } }
在組件的事件中,Redux
中只需把 action
建立函數的結果傳給 dispatch()
方法便可發起一次 dispatch
過程。
dispatch(addTodo(text))
或者
const boundAddTodo = (text) => dispatch(addTodo(text)) boundAddTodo(text);
如上所示,咱們每次都須要調用時dispatch這個action。
在 React 組件中,若是你但願讓組件經過調用函數來更新 state,能夠經過使用 const actions = bindActionCreators(FilmActions, dispatch); 將 actions 和 dispatch 揉在一塊兒,成爲具有操做 store.state 的 actions。
Action 只是描述了有事情發生了這一事實,並無指明應用如何更新 state。而這正是 reducer 要作的事情。
當明確action的任務,就能夠開始編寫 reducer,並讓它來處理以前定義過的 action。
//reducers import { addTodo,ADD_TODO } from './actions' function todoApp(state = initialState, action) { switch (action.type) { case ADD_TODO: return Object.assign({}, state, { text: action.text }) default: return state } }
注意:
不要修改 state。 使用 Object.assign() 新建了一個副本。爲了對ES7提案對象展開運算符的支持, 也能夠使用 { ...state, ...newState } 達到相同的目的。
在 default 狀況下返回舊的 state。遇到未知的 action 時,必定要返回舊的 state。
reducer中的一個fun在store裏做爲一個對象存儲。
combineReducers() 所作的只是生成一個函數,這個函數來調用你的一系列 reducer,每一個 reducer 根據它們的 key 來篩選出 state 中的一部分數據並處理,而後這個生成的函數再將全部 reducer 的結果合併成一個大的對象。
import { combineReducers } from 'redux'; const todoApp = combineReducers({ todoApp }) export default todoApp;
Store
就是把action
和reducer
聯繫到一塊兒的對象。Store
有如下職責:
維持應用的 state
;
提供 getState()
方法獲取 state
;
提供 dispatch(action)
方法更新 state
;
經過 subscribe(listener)
註冊監聽器;
經過 subscribe(listener)
返回的函數註銷監聽器。
Redux
應用只有一個單一的store
。當須要拆分數據處理邏輯時,你應該使用reducer
組合 而不是建立多個store
。
咱們使用 combineReducers()
將多個 reducer
合併成爲一個。如今咱們將其導入,並傳遞 createStore()
。
import { createStore } from 'redux' import todoApp from './reducers' let store = createStore(todoApp)
redux
中的middleware
仍是比較簡單的,它只是針對於dispatch
方法作了middleware
處理;也就是說,只接受一個action
對象;
import createLogger from 'redux-logger'; import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import reducers from './reducers'; const logger = createLogger(); let thunkStore = applyMiddleware(thunk,logger)(createStore); let store = thunkStore(reducers);
connect(mapStateToProps, mapDispatchToProps, mergeToProps)(App);
第一個函數接收store中state和props,使頁面能夠根據當前的store中state和props返回新的stateProps
;
第二個函數接收store中的dispatch和props,使頁面能夠複寫dispatch方法,返回新的dispatchProps
;
第三個函數接收前2個函數生成的stateProps
和dispatchProps
,在加上原始的props
,合併成新的props
,並傳給原始根節點的props
。
const mapStateToProps = (state, ownProps) => { return { active: ownProps.filter === state.visibilityFilter } } const mapDispatchToProps = (dispatch, ownProps) => { return { onClick: () => { dispatch(setVisibilityFilter(ownProps.filter)) } } } const FilterLink = connect( mapStateToProps, mapDispatchToProps )(Link)
<Provider store> 使組件層級中的 connect() 方法都可以得到 Redux store。正常狀況下,你的根組件應該嵌套在 <Provider> 中才能使用 connect() 方法。
react-redux
首先提供了一個Provider
,能夠將從createStore
返回的store
放入context
中,使子集能夠獲取到store
並進行操做;
Connect 組件須要 store。這個需求由 Redux 提供的另外一個組件 Provider 來提供。源碼中,Provider 繼承了 React.Component,因此能夠以 React 組件的形式來爲 Provider 注入 store,從而使得其子組件可以在上下文中獲得 store 對象。
<Provider store={store}> <App/> </Provider>