带你了解redux与react-redux

1、redux

1.1)Action Creator

export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';
----
import * as types from '../action-types';
//actionCreator 创建action的函数
export default {
    increment(){
        return {type:types.INCREMENT}
    },
    decrement(){
        return {type:types.DECREMENT}
    }

}
复制代码

看着写了这么多,其实就是为了拿到字符串INCREMENTDECREMENT

1.2)reducer

reducer是一个纯函数,相同的输入有相同的输出,不同的输入得到不同的输出。它必须遵守以下几点

  • 不得改写参数
  • 不能调用系统 I/O 的API
  • 不能调用Date.now()或者Math.random()等不纯的方法,因为每次会得到不一样的结果

reducer中不能改变state,在保证旧的状态不变的情况下,返回一个全新的状态

const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
let initState = { number: 0 }
export default function (state = initState, action) {
    switch (action.type) {
        case INCREMENT:
            return { number: state.number + 1 };
        case DECREMENT:
            return { number: state.number - 1 };
        default:
            return state;
    }
}
复制代码

其实就相当于state变成了一个只是可读的状态,不可更改,返回了计算后的新的状态,原状态不变。

1.3)createStore

const createStore = (reducer) => {
  let state;
  let listeners = [];
  
  const getState = () => state;// 因为dispatch的执行,拿到的是初始状态
  
  //订阅,供外界订阅本仓库中状态的变化 ,如果状态变化 了会执行订阅的逻辑 
  const subscribe = (listener) => {
  listeners.push(listener);
    return () => {//subscribe的返回结果是一个unsubscribe
      listeners = listeners.filter(l => l !== listener);
    }
  };

  const dispatch = (action) => {
  //接收新的动作后,通过 才状态 和新动作计算出新状态
    state = reducer(state, action);
    listeners.forEach(listener => listener());
  };

  dispatch({});
  // 这里执行dispatch的原因是,为了运行reducer函数,最终获取到里面的初始 state,也就是说createStore()执行后,立马拿到初始状态。
  return { getState, dispatch, subscribe };
};
复制代码

1.4)combinReducers

将两个reducer合并

 function combineReducers(reducers) {
     //返回合并后的reducer,这个函数将被传入createStore
     return function (state = {}, action) {
         let newState = {};
         for (let attr in reducers) {
             let reducer = reducers[attr];
             newState[attr] = reducer(state[attr], action);
         }
         return newState;
     }
 }
 export default combineReducers({
    reducer1,
    reducer2
});
复制代码

另外一种写法:

export default reducers => (state = {}, action) => Object.keys(reducers).reduce((currentState, key) => {
    currentState[key] = reducers[key](state[key], action);
    return currentState;
}, {});
复制代码

1.5)bindActionCreator

我们做下面一个操作

<button onClick={()=>store.dispatch(actions.increment())}>-</button>
复制代码

bindActionCreator用来把actiondispatch绑定在一起,让书写变得更方便

<button onClick={newActions.increment}>-</button>
复制代码

这是bindActionCreators的实现原理:

function bindActionCreators(actions,dispatch){
    let newActions = {};
    for(let attr in actions){
     newActions[attr] = function(){
         dispatch(actions[attr].apply(null,arguments));
     }
    }
    return newActions;
 }
复制代码

1.6) 我们可以来生成redux了

import createStore from './createStore';
import combineReducers from './combineReducers';
import bindActionCreators from './bindActionCreators';
export {
    createStore,
    combineReducers,
    bindActionCreators
}
复制代码

二、react-redux

1、Provider

provider的作用是让每个组件都拥有调用store的能力

Provider 本身并没有做很多事情,只是把store放在 context 里罢了。实际上如果你用 react-redux,那么连接视图和数据层最好的办法是使用 connect 函数。本质上 Provider就是给 connect提供store用的。

//用来通过上下文对象向下层组件传递数据 store
import React,{Component} from 'react';
import propTypes from 'prop-types';
export default class Provider extends Component{
    static childContextTypes = {
        store:propTypes.object.isRequired
    }
    getChildContext(){
        return {store:this.props.store};
    }
    render(){
        return this.props.children;
    }
}
复制代码

一般我们在跟组件上使用

const store = configureStore();
render(
   <Provider store={store}>
      <Root />
   </Provider>,
   document.getElementById('root')
);
复制代码

2、connect

React-Redux 提供connect方法,用于从 UI 组件生成容器组件。connect的意思,就是将这两种组件连起来。

作用:

  • (1)输入逻辑:外部的数据(即state对象)如何转换为UI 组件的参数

  • (2)输出逻辑:用户发出的动作如何变为 Action对象,从 UI 组件传出去

connect的使用

import { connect } from 'react-redux'

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
复制代码

connect有两个参数,分别是 mapStateToProps,mapDispatchToProps

第一个参数负责输入逻辑,即将state映射到 UI 组件的参数(props),第二个参数负责输出逻辑,即将用户对UI 组件的操作映射成 Action

2.1 ) mapStateToProps

返回值,是一个对象.

从字面上理解,就是把状态(store中的state)映射成属性(组件中的props)

const mapStateToProps = (state) => ( // 正常我们在react-redux中会这样书写
  {number: state.number}
  )
复制代码
2.2)mapDispatchToProps

mapDispatchToPropsconnect函数的第二个参数,用来建立 UI 组件的参数到store.dispatch方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。

如果mapDispatchToProps是一个函数,会把dispatch当做一个参数传进去。

const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => {
      dispatch({
        type: 'ADD'
      });
    }
  };
}
// 返回了一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。
复制代码

如果mapDispatchToProps是一个对象,它的每个键名也是对应 UI 组件的同名参数,键值应该是一个函数,会被当作 Action creator ,返回的 Action 会由 Redux 自动发出。

bindActionCreators(mapDispatchToProps,this.store.dispatch)
复制代码
2.3) 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;//这里的store是从Prodiver传过来的
            this.state = mapStateToProps(this.store.getState());//{color:state.color}
          }
          componentWillMount(){
              this.unsubscribe = this.store.subscribe(()=>{
                  this.setState(mapStateToProps(this.store.getState()));// 根据store中的state来更新视图。
              });
          }
          componentWillUnmount(){
              this.unsubscribe();
          }
          render(){
              let actions= {};
              if(typeof mapDispatchToProps == 'function'){
                actions = mapDispatchToProps(this.store.disaptch);
              }else if(typeof mapDispatchToProps == 'object'){
                actions = bindActionCreators(mapDispatchToProps,this.store.dispatch);
              }
                return <WrapedComponent {...this.state} {...actions}/>
         }
      }
      return ProxyComponent;
   }
}
复制代码
2.4) 最后我们来生成react-redux
import connect from './connect';
import Provider from './Provider';
export {
    connect,
    Provider
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值