redux是react全家桶的一員,它試圖爲 React 應用提供「可預測化的狀態管理」機制。react
Redux是將整個應用狀態存儲到到一個地方,稱爲storegit
裏面保存一棵狀態樹(state tree)github
組件能夠派發(dispatch)行爲(action)給store,而不是直接通知其它組件npm
其它組件能夠經過訂閱store中的狀態(state)來刷新本身的視圖redux
npm install --save redux
複製代碼
4.1 Statebash
state是數據集合ide
能夠理解爲工廠加工商品所需的原材料函數
4.2 actionui
State的變化,會致使View的變化。可是,用戶接觸不到 State,只能接觸到View 因此,State的變化必須是 View致使的。this
action就是改變state的指令,有多少操做state的動做就會有多少action。
能夠將action理解爲描述發生了什麼的指示器
4.3 reducer 加工函數
action發出命令後將state放入reucer加工函數中,返回新的state。 能夠理解爲加工的機器
4.4 store
store 能夠理解爲有多個加工機器的總工廠
let store = createStore(reducers);
複製代碼
Store 就是把它們聯繫到一塊兒的對象。Store 有如下職責:
維持應用的 state;
提供 getState() 方法獲取 state;
提供 dispatch(action) 方法更新 state;
經過 subscribe(listener) 註冊監聽器;
經過 subscribe(listener) 返回的函數註銷監聽器。
複製代碼
咱們能夠經過store.getState()來了解工廠中商品的狀態, 使用store.dispatch發送action指令。
這是一個redux的經典案例
import { createStore } from 'redux'
const reducer = (state = {count: 0}, action) => {
switch (action.type){
case 'INCREASE': return {count: state.count + 1};
case 'DECREASE': return {count: state.count - 1};
default: return state;
}
}
const actions = {
increase: () => ({type: 'INCREASE'}),
decrease: () => ({type: 'DECREASE'})
}
const store = createStore(reducer);
store.subscribe(() =>
console.log(store.getState())
);
store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}
複製代碼
咱們能夠直接在react component上使用store.dispatch,可是這樣不太方便,這個時候咱們須要react-redux
class Todos extends Component {
render(){
return(
<div onCLick={()=>store.dispatch(actions.delTodo()) }>test</div>
)
}
}
複製代碼
Redux 官方提供的 React 綁定庫。 具備高效且靈活的特性。
6.1 安裝
npm install --save react-redux
複製代碼
6.2 核心
Provider 內的任何一個組件(好比這裏的 Comp),若是須要使用 state 中的數據,就必須是「被 connect 過的」組件——使用 connect 方法對「你編寫的組件(MyComp)」進行包裝後的產物。
這個函數容許咱們將 store 中的數據做爲 props 綁定到組件上。
簡單的流程以下圖所示:
react-redux中的connect方法將store上的getState 和 dispatch 包裝成組件的props。
將以前直接在組件上dispatch的代碼修改成以下:
index.js
import React, { Component } from 'react';
import store from '../store';
import actions from '../store/actions/list';
import {connect} from 'react-redux';
class Todos extends Component {
render(){
return(
<div onCLick={()=>this.props.del_todo() }>test</div>
)
}
}
export default connect(
state=>state,
actions
)(Todos);
複製代碼
Provider 能拿到關鍵的store並傳遞給每一個子組件
connect() 接收四個參數,它們分別是 mapStateToProps , mapDispatchToProps, mergeProps 和 options 。
7.1 mapStateToProps這個函數容許咱們將 store 中的數據做爲 props 綁定到組件上。
reducer.js
export default function (state = { lists: [{text:'移動端計劃'}],newType:'all'}, action) {
switch (action.type) {
case types.ADD_TODO:
return {...state,lists:[...state.lists,{text:action.text}]}
case types.TOGGLE_TODO:
return {...state,lists:state.lists.map((item,index)=>{
if(index == action.index){
item.completed = !item.completed
}
return item
})}
case types.DEL_TODO:
return {...state,lists:[...state.lists.slice(0,action.index),...state.lists.slice(action.index+1)]}
case types.SWITCH_TYPE:
console.log({...state,newType:action.newType})
return {...state,newType:action.newType}
default:
return state;
}
}
複製代碼
在reducer.js中,定義了初始化的state,經過connect方法,咱們就能使用this.props.lists拿到初始化的state。
import React, { Component } from 'react';
import store from '../store';
import actions from '../store/actions/list';
import {connect} from 'react-redux';
class Todos extends Component {
render(){
return(
{
+ <ul>
+ this.props.state.lists.map(list =>(
+ <li>{list.text}</li>
+ ))
+ </ul>
}
<div onCLick={()=>this.props.del_todo() }>test</div>
)
}
}
export default connect(
state=>state,
actions
)(Todos);
複製代碼
當 state 變化,或者 ownProps 變化的時候,mapStateToProps 都會被調用,計算出一個新的 stateProps,(在與 ownProps merge 後)更新給 MyComp。
7.2 mapDispatchToProps(dispatch, ownProps): dispatchProps connect 的第二個參數是 mapDispatchToProps,它的功能是,將 action 做爲 props 綁定到 MyComp 上。
action.js
import * as types from "../action-types";
export default{
add_todo(text){
return { type: types.ADD_TODO, text: text}
},
del_todo(idx){
return {type:types.DEL_TODO, index: idx}
},
toggle_todo(index){
return {type:types.TOGGLE_TODO, index}
},
del_todo(index){
return {type:types.DEL_TODO, index}
},
switch_type(newType){
return {type:types.SWITCH_TYPE, newType}
}
}
複製代碼
我在action.js中定義的修改狀態的命令,會經過connect 的 mapDispatchToProps方法變爲props綁定在reac組件上。
咱們能夠方便得使用去調用
<div onCLick={()=>this.props.del_todo() }>test</div>
複製代碼
瞭解到這裏,咱們會發現並無使用store.dispatch方法去發出命令,可是state已經修改,view也變化了,那麼到底發生了什麼?
store.dispatch(actions.increase())
複製代碼
關鍵的是connect()
connect原理簡化版
import React,{Component} from 'react';
import {bindActionCreators} from 'redux';
import propTypes from 'prop-types';
export default function(mapStateToProps,mapDispatchToProps){
return function(WrapedComponent){
class ProxyComponent extends Component{
static contextTypes = {
store:propTypes.object
}
constructor(props,context){
super(props,context);
this.store = context.store;
this.state = mapStateToProps(this.store.getState());
}
componentWillMount(){
this.unsubscribe = this.store.subscribe(()=>{
this.setState(mapStateToProps(this.store.getState()));
});
}
componentWillUnmount(){
this.unsubscribe();
}
render(){
let actions= {};
if(typeof mapDispatchToProps == 'function'){
actions = mapDispatchToProps(this.store.disaptch);
}else if(typeof mapDispatchToProps == 'object'){
console.log('object', mapDispatchToProps)
actions = bindActionCreators(mapDispatchToProps,this.store.dispatch);
}
return <WrapedComponent {...this.state} {...actions}/>
}
}
return ProxyComponent;
}
}
複製代碼
1.state的返回 connect中對於Provided父組件上傳來的store,經過將狀態返回
mapStateToProps(this.store.getState());
複製代碼
經過 Redux 的輔助函數 bindActionCreators(),用dispatch監聽每個action。
bindActionCreators(mapDispatchToProps,this.store.dispatch);
複製代碼
因此調用props上的方法時,會自動發起store.dispach(XXX)事件,發出命令
react-redux到這裏分析結束,後面會繼續寫redux中間件的相關文章!