redux基础

介绍 Redux

  • Redux是一个数据状态管理插件,搭配 React 特别合适,详细的用法可见Redux官网

使用场景

  • 无论是移动端还是 pc 端,当你使用 React 或者 vue 开发组件化的 SPA 程序时,组件之间共享信息是一个非常大的问题。
  • 因此每个系统都需要一个管理多组件使用的公共信息的功能,这就是 Redux 的作用。同理,vue 也有相应的工具,即 vuex ,可以自己去 github 上搜索相关资料。
  • 只要使用 React 开发系统,你绝大部分都需要结合 Redux 来使用

安装

  • 如果单纯使用 Redux 仅仅安装 Redux 即可,执行npm install redux –save,不过在 React 中使用 Redux 肯定会用到 react-redux 这一工具,因此这里一起安装完,执行npm install react-redux –save。

基本使用

  • redux 中的入门demo

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    import { createStore } from 'redux'
    export default function () {
    // 下面这一段代码,就是 https://github.com/reactjs/redux 中的入门demo
    // 定义计算规则,即 reducer
    function counter(state = 0, action) {
    switch (action.type) {
    case 'INCREMENT':
    return state + 1
    case 'DECREMENT':
    return state - 1
    default:
    return state
    }
    }
    // 根据计算规则生成 store
    let store = createStore(counter)
    // 定义数据(即 state)变化之后的派发规则
    store.subscribe(() => {
    console.log('current state', store.getState())
    })
    // 触发数据变化
    store.dispatch({type: 'INCREMENT'})
    store.dispatch({type: 'INCREMENT'})
    store.dispatch({type: 'DECREMENT'})
    }
  • Redux 是一个管理数据的工具,我们创建一个store变量用来管理数据。

  • 创建store用来管理数据,具体的管理形式是什么呢?
    • 第一,要通过一个函数来触发数据的变化,即dispatch,触发的时候一定要符合之前定制的规则,否则无效
    • 第二,数据一旦发生变化时,会导致怎样后果,即subscribe中定义的函数会执行。
    • 第三,如何取得当前的数据,即store.getState()。
  • 还有一点特别要注意,即在规则函数中,数据变化时要return一个新的值,而不是直接修改原来的值。

Redux 和 React 结合使用

  • 以下请参考redux-demo项目
  • 创建 store

    • 首先也需要创建一个store,参见/src/store/index.js的代码。创建store之前要有规则,这里的第一个参数就是这个规则

      1
      2
      3
      4
      5
      import {createStore} from 'redux'
      import rootReduer from '../reducers'
      const store = createStore(rootReduer, window.devToolsExtension ? window.devToolsExtension() : undefined)
      export default store
    • 第二个参数即初始化的数据,第三个参数可调起 chrome 扩展程序,具体可参见 redux-devtools

  • 创建规则(Reducer)
    • 使用 Redux 时,刚才提到的“规则”被称作reducer,因此这里的数据规则代码都在/src/reducers目录下。
    • /src/constants/userinfo.js中这些 const 会在多个文件中使用,因此要抽象出来。
    • /src/reducers/index.js中 用combineReducers这个函数对/src/reducers/userinfo.js的数据进行了封装,这样做是为了更好的扩展性。
    • 数据结构如果复杂,必须分组管理。因此我们需要用state.userinfo来表示用户数据—这就是用combineReducers封装各个 reducer 的作用。
  • 创建 action
    • 上面的 demo 中,最后执行数据变化时store.dispatch({type: ‘INCREMENT’}),这里的{type: ‘INCREMENT’}是我们手动写上的,而在实际的应用中,我们需要用一些函数将它封装起来,即/src/actions中的文件,虽然此处只有userinfo.js这一个文件。
    • /src/actions/userinfo.js中,我们把每个业务操作都封装为一个函数,该函数接收data,然后再根据 reducer 的规则对 data 进行封装,最后返回。当然,最后返回的结果肯定还是会交给dispatch来处理。
  • Redux结合到 React

    • 创建了store并传递给组件,然后让组件作为所有组件的根节点

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      import React from 'react'
      import {render} from 'react-dom'
      import App from './App'
      import {Provider} from 'react-redux'
      import store from './store'
      render(
      <Provider store={store}>
      <App/>
      </Provider>,
      document.getElementById('root')
      )
    • 然后看./src/App.js,注意下面这些代码。通过下面的封装,就把userinfo和userinfoActions当做props传入到App组件中了,即在App组件中通过this.props.userinfo和this.props.userinfoActions即可获取数据和actions

      1
      2
      3
      4
      5
      6
      7
      function mapStateToProps(state) {
      return { userinfo: state.userinfo }
      }
      function mapDispatchToProps(dispatch) {
      return { userinfoActions: bindActionCreators(userinfoActions, dispatch) }
      }
      export default connect( mapStateToProps, mapDispatchToProps )(App)
    • 获取了数据和 actions 该怎么用呢?我们将它们传递给子组件,A和B组件负责展示数据,C组件负责触发actions。具体可参见各个组件的源代码。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      render() {
      return (
      <div>
      <p>hello world</p>
      <hr/>
      <A userinfo={this.props.userinfo}/>
      <hr/>
      <B userinfo={this.props.userinfo}/>
      <hr/>
      <C userinfoActions={this.props.userinfoActions}/>
      </div>
      )
      }