深入理解redux之从redux源码到react-redux的原理

栏目: IOS · Android · 发布时间: 6年前

内容简介:在使用react的过程中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,比如reducer在redux中时怎么发挥作用的,为什么只要写好reducer,和dispatch特定action配合,store的状态就会更新了,而react组件又是如何和store的状态产生关系的,为什么随着store状态的更新,react组件会被自动更新,下面就从redux的源码开始来总结下这其中的缘由~redux是继承自flux体系,但它放弃了dispatcher,无需使用 event emitters(

在使用react的过程中,用redux来管理应用中的状态,使应用流更清晰的同时也会有小小的疑惑,比如reducer在redux中时怎么发挥作用的,为什么只要写好reducer,和dispatch特定action配合,store的状态就会更新了,而react组件又是如何和store的状态产生关系的,为什么随着store状态的更新,react组件会被自动更新,下面就从redux的源码开始来总结下这其中的缘由~

redux管理状态的原理

redux是继承自flux体系,但它放弃了dispatcher,无需使用 event emitters(事件发送器)(在dispatcher中特定action逻辑里触发事件,组件里监听事件),而使用纯 reducer来代替,那么reducer是如何被调度的,又是如何影响状态更新的,不妨通过源码的逻辑来了解和加深一下~

从redux源码看action,reducer,和store之间的关系

reducer通常是由我们自己来写,在调用 createStore 函数生成store时来传入这个 reducer ,后续调用 storedispatch 方法来触发 action 时,则 reducer 函数会自动被调用来解析 actin 更新 state ,这一切的核心都在 crateStore 方法中

export  default function createStore(reducer, preloadedState, enhancer) {
    ...
    let currentReducer = reducer
    let currentState = preloadedState
    let currentListeners = []
    let nextListeners = currentListeners
    let isDispatching = false
    function getState() {
       ...
    }
    function subscribe(listener) {
        ...
    }
    function dispatch(action) {
        ...
    }
    function replaceReducer(nextReducer) {
        ...
    }
    function observable() {
        ...
    }
    return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
}
复制代码

可以看到createStore方法返回一个属性集合,我们所调用的redux的相关方法都是定义在createStroe方法内部,最后被通过这个属性集合中暴露出来,如处理action的dispath方法,同currentReducer,currentState是createStore方法中的私有变量,由dispath,subscribe,getState等方法共享,我们设置的reducer,redux的state状态,以及state改变之后应该自动触发哪些函数,这些逻辑都是通过这几个内部变量和函数来实现的,下面先来看一下几个核心方法,由我们直接接触到的dispath开始~

dispacth处理action

function dispatch(action) {
    ...
    try {
      //将flag置为true,表明处于分发逻辑中
      isDispatching = true 
      
      //currentReducer即为函入的reducer函数,这里会自动调用currentReducer函数,并将返回值赋给currentState
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    
    //调用监听函数
    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
    return action
}
复制代码

可以看到,在dispath中调用reducer方法处理action之后,返回值(新的state)会直接赋值给 currentState ,由此可以推测 currentState 应该就是 getState 要返回的状态

getState返回当前的状态

function getState() {
    if (isDispatching) {
      throw new Error(
      ...
      )
    }
    return currentState //直接返回currentState内部变量
  }
复制代码

subscribe订阅状态

function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error(...)
    }
    if (isDispatching) {
      throw new Error(
        ...
      )
    }
    let isSubscribed = true
    ...
    nextListeners.push(listener)

    return function unsubscribe() {
      ...
    }
复制代码

在subscribe中,传入的listener函数会被添加进nextListeners数组中,当dispatch方法被调用时自动触发,react-redux的状态更新时,UI自动更新的特性是通过subscribe来实现的

通过redux来管理react的状态

首先,设想我们不知道react-redux库来连接react和redux,来试一下单纯的通过redux作为react组件的状态管理器

创建store

//首先,创建一个reducer处理函数
function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return ...
    case ADD_TODO:
      return ...
    default:
      return state
  }
}
//创建store
const store = createStore(
  todoApp
);
复制代码

各组件之间共享store的状态

要在各组件之间共享变量store有两种方式可取,一种是通过props共享,一种是通过context实现,其中props共享变量需要每一层组件之间层层传递该变量,这样做无疑很麻烦,尤其是组件之前嵌套层次比较深的时候,所以我们这里用react的context属性来实现共享store

根组件提供context

class App extends Component {
  getChildContext() {
    return {
      store: this.props.store
    };
  }
  render() {
    return <ToDoList />;
  }
}

App.childContextTypes = {
  store: React.PropTypes.object
}
复制代码

子组件获取context

class VisibleTodoList extends Component {
  componentDidMount() {
    const { store } = this.context;
    this.unsubscribe = store.subscribe(() =>
      this.forceUpdate()
    );
  }

  render() {
    const props = this.props;
    const { store } = this.context;
    const state = store.getState();
    // ...
  }
}

VisibleTodoList.contextTypes = {
  store: React.PropTypes.object
}

复制代码

如上所示,在需要获取store状态的组件中,在组件加载完成后需要获取关心得context的变量值store,同时订阅事件,当store的状态变化后触发组件本身的强制更新,而render中只需用 store.getState 获取store的状态值即可

用react-redux来简化组件的写法

上例中写了一个组件的实现还好,但当组件多的时候,每个组件都需写自己的获取context,订阅事件强制更新自身,获取state,这样的样板代码,实际是没必要的,完全可以把这部分抽象出来,而react-redux就帮我们做了这些,让我们省去了自定义context和订阅事件,获取state等操作

省去自定义含有context属性的根组件

要利用 redux 来管理状态,需要在祖先组件的 context 属性中指定 store ,而这一定式化的操作可以有 react-redux 库中的 Provider来完成 ,示例如下

<Provider store={store}>
    <App />
  </Provider>
复制代码

省去手动订阅store的状态变化事件

上节中提到过,要实现store的状态更新后能自动更新react组件,则组件需在挂载后调用 storesubscribe 方法来订阅 store 中状态的变更,而这块儿样板代码则可以由 react-redux 库中的 connect 创建的容器组件来自动完成

class TodoList extends Component {
 render(){
     ...
 }
}
const mapStateToProps = state => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}
const mapDispatchToProps = dispatch => {
  return {
    onTodoClick: id => {
      dispatch(toggleTodo(id))
    }
  }
}
const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
复制代码

其中mapStateToProps提供从Redux store state到展示组件的 props的映射 ,mapDispatchToProps接收dispatch方法并提供期望注入到展示组件的 props 中的回调方法。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Types and Programming Languages

Types and Programming Languages

Benjamin C. Pierce / The MIT Press / 2002-2-1 / USD 95.00

A type system is a syntactic method for automatically checking the absence of certain erroneous behaviors by classifying program phrases according to the kinds of values they compute. The study of typ......一起来看看 《Types and Programming Languages》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具