美文网首页
浅入 Redux

浅入 Redux

作者: 风之伤_3eed | 来源:发表于2018-09-04 18:34 被阅读0次

    Redux 三大核心

    Redux的核心由三部分组成:Store, Action, Reducer。

    Store : 是个对象,贯穿你整个应用的数据都应该存储在这里。
    Action: 是个对象,必须包含type这个属性,reducer将根据这个属性值来对store进行相应的处理。除此之外的属性,就是进行这个操作需要的数据。
    Reducer: 是个函数。接受两个参数:要修改的数据(state) 和 action对象。根据action.type来决定采用的操作,对state进行修改,最后返回新的state。

    ===== Store =====
    {
      todos: [],
      visibilityFilter: 'SHOW_ALL'
    }
    
    
    ===== Action =====
    {
      type: 'ADD_TODO',
      text: 'Build my first Redux app'
    }
    
    ===== Reducer =====
    const todos = (state = [], action) => {
      switch (action.type) {
        case 'ADD_TODO':
          return [
            ...state,
            {
              id: action.id,
              text: action.text,
              completed: false
            }
          ]
        default:
          return state
      }
    }
    

    Redux核心之间的关系

    我们触发action → reducer来处理。这就是二者之间的关系。那么我们怎么触发action呢?Store这个对象提供了dispatch方法 → 触发action。dispatch方法接受action对象作为参数。因此,我们可以了解三者之间的关系:

    store ➡️ dispatch ➡️ action ⬅️ reducer
    Store
    我们通过redux提供的createStore这个方法来创建一个Store。它接受对store进行处理的reducer作为参数。

    Store有三个方法:

    getState:用来获取store里面存储的数据。
    dispatch: store里的数据不能直接修改,只能通过触发action来进行修改,这个方法就是用来触发action。
    subscibe:订阅store改变时,要进行的操作。比如在react中,当store改变时,我们需要调用render方法对视图进行更新。

    const store = createStore(reducer);
    
    store.getState(); // { todos: [], visibilityFilter: 'SHOW_ALL' }
    
    store.dispatch({
      type: 'ADD_TODO',
      text: 'Build my first Redux app'
    });
    
    store.subscibe(() => {
      console.log(store.getState());
    });
    

    Reducer

    我们可以将对store的操作,写在一个reducer中,比如:

    function todoApp(state = initialState, action) {
      switch (action.type) {
        case SET_VISIBILITY_FILTER:
          return Object.assign({}, state, {
            visibilityFilter: action.filter
          })
        case ADD_TODO:
        case TOGGLE_TODO:
          return Object.assign({}, state, {
            todos: todos(state.todos, action)
          })
        default:
          return state
      }
    }
    

    可以看到这个reducer对store的visibilityFilter和todos的两部分数据进行了处理。随着应用的复杂,如果我们把对所有数据的处理,都写在一个reducer中,那么它会变得很冗杂。如果我们将对每一部分的数据的处理,写在一个单独的reducer中,它接受该部分的数据作为state。那么整个reducer会变得整洁和清晰。

    因此,redux为我们提供了combineReducer这个API,帮助我们分开书写reducer, 并且最终把这些reducer给集合到一个根reducer中。

    // 对todos进行处理
    function todos(state = [], action) {
      switch (action.type) {
        case ADD_TODO:
          return [
            ...state,
            {
              text: action.text,
              completed: false
            }
          ]
        default:
          return state
      }
    }
    
    // 对 visibilityFilter 进行处理
    function visibilityFilter(state = SHOW_ALL, action) {
      switch (action.type) {
        case SET_VISIBILITY_FILTER:
          return action.filter
        default:
          return state
      }
    }
    
    // 生成 root reducer
    function todoApp(state = {}, action) {
      return {
        visibilityFilter: visibilityFilter(state.visibilityFilter, action),
        todos: todos(state.todos, action)
      }
    }
    
    // 创建store
    const store = createStore(todoApp)
    

    react-redux

    上一部分我们介绍了redux的核心。可以看到,redux是独立的应用状态管理工具。它是可以独立于react之外的。如果我们需要在react当中运用它,那么我们需要手动订阅store的状态变化,来对我们的react组件进行更新。那么react-reudx这个工具,就帮我们实现了这个功能,我们只需对store进行处理,react组件就会有相应的变化。

    这个工具主要提供两个API:

    connect

    现在我们有了store,那么我们怎么才能在我们的组件中对它们进行操作呢?connect就为提供了这个功能。它接受mapStateToProps, mapDispatchToProps等作为参数。比如在我的TodoList这个组件中需要用到todos这部分数据,那么我完善mapStateToProps这个函数,它接受store中的state作为参数,返回一个对象,属性就是state中我们需要的数据:

    const mapStateToProps = state => {
      return {
        todos: state.todos
      }
    }
    

    mapStateToProps就将我们的state转换为了props对象。

    同样的,我们可能需要在组件中对state进行处理。mapDispatchToProps就是帮助我们在组件中通过props调用dispatch来触发action的:

    const mapDispatchToProps = dispatch => {
      return {
        onTodoClick: id => {
          dispatch(toggleTodo(id))
        }
      }
    }
    

    最后我们调用connect这个方法,将mapStateToProps, mapDispatchToProps生成的props注入到需要使用它的组`中:

    const VisibleTodoList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoList)
    

    这样,我们在TodoList这个组件中,就能直接通过props.todos获取到todos中的数据, 通过props.onTodoClick对todos进行处理。

    provider

    上面我们调用connect时,在mapStateToProps 和 mapDispatchToProps我们分别用到了store的state和dispatch。但是在组件中的store是哪里凭空冒出来的呢?

    provider就是来解决这个事的。Provider使它的子孙在调用connect方法时,都能获取到store。

    const VisibleTodoList = connect(
      mapStateToProps,
      mapDispatchToProps
    )(TodoList)
    
    const App = () => (
      <div>
        <AddTodo />
        <VisibleTodoList />
        <Footer />
      </div>
    )
    
    <Provider store={store}>
      <App />
    </Provider>
    

    这样,Provider的子孙组件都能在调用connect时获取到store。

    相关文章

      网友评论

          本文标题:浅入 Redux

          本文链接:https://www.haomeiwen.com/subject/tkrnwftx.html