react-redux到底是什麼

1. 目錄

  • redux簡介
  • 案例
  • react-redux核心介紹

2. redux簡介

  • redux是react全家桶的一員,它試圖爲 React 應用提供「可預測化的狀態管理」機制。

  • Redux是將整個應用狀態存儲到到一個地方,稱爲store

  • 裏面保存一棵狀態樹(state tree)

  • 組件可以派發(dispatch)行爲(action)給store,而不是直接通知其它組件

  • 其它組件可以通過訂閱store中的狀態(state)來刷新自己的視圖

3. 安裝

npm install --save redux
複製代碼

4. redux核心

4.1 State

state是數據集合

可以理解爲工廠加工商品所需的原材料

4.2 action

State的變化,會導致View的變化。但是,用戶接觸不到 State,只能接觸到View 所以,State的變化必須是 View導致的。

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指令。

5. 經典案例

這是一個redux的經典案例

  • 定義reducer函數根據action的類型改變state
  • actions 定義指令
  • 通過createStore創建store
  • 調用store.dispatch()發出修改state的命令
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>
        )
    }
}
複製代碼

6. react-redux

Redux 官方提供的 React 綁定庫。 具有高效且靈活的特性。

6.1 安裝

npm install --save react-redux
複製代碼

6.2 核心

  • < Provider store>
  • connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

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並傳遞給每個子組件

7. connect如何工作的?

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>
複製代碼

8. 深入

瞭解到這裏,我們會發現並沒有使用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)事件,發出命令

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章