redux的数据流

时间:2024-03-29 22:25:01

redux的data flow

redux是JavaScript的状态容器, 通过redux, 我们可以轻松的对状态进行管理.
redux的data flow如下所示:
redux的数据流
(图片来源于慕课网)
store存储着状态, 要想改变store必须使用action, store进行更新时使用reducer. 那么store, action, reducer是啥呢?
store和action都是对象, action中必须有一个type字段对进行的操作进行说明, 可能会有数据. store会赋值给组件中的state
reducer是一个纯函数, 接收两个参数, 第一个参数是累积对象(即state), 第二个参数就是action. reducer函数根据action.type的不同对state进行操作, 最后返回一个新的state, 这个新的state同时又是下一次的累积对象.
从图中可以看书store.dispatch(action)会要求改变store.

案例

我通过一个简单的加减一来描述state是如何更新的.
假设我们已经使用create-react-app脚手架工具创建好了项目目录. 保留src/目录中的index.js和App.js文件, src/目录下的其他文件全部删除.
index.js是程序的入口文件, 而App.js是具体内容挂载到public/index.html里id为"root"的元素中.

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

同时用下面的代码覆盖原来的App.js文件.

import React, { Component } from 'react';
import 'antd/dist/antd.css';
import { Button } from 'antd'

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
    	number: 1
    }
  }
  render() {
    return (
      <div>
        <div className="App" style={{marginLeft: '10px', marginBottom: '20px'}}>
          <div>{this.state.number}</div>
          <Button type="primary" >
            +
          </Button>
          <Button>
            -
          </Button type="primary" >
        </div>
      </div>
    )
  }
}
export default App;

这里我们使用了antdUI组件库, 因此注意先安装.
打开命令行执行命令npm start后显示如下:
redux的数据流

我想实现这样一个需求, 当点击加号时, 数字加1, 点击减号时, 数字减一. 由于我们使用redux来管理状态, 那么就先引入redux, 并创建一个store.

import { createStore } from 'redux'
//store
const store = createStore()

再创建一个reducer.

//reducers
const defaultState = {
  number: 1
}
function reducer(state = defaultState, action) {
	//some codes
  return state
}

我们使用defaultState来初始化数据. 并将reducer传递给store.createStore作为参数, 这样strore就会根据reducer来初始化值了. 这个值就是defaultState. reducer返回的新state会传给store, store再通过subscribe来触发更新

const store = createStore(reducer)

然后将App组件里constructor中的state使用store来初始化.

class App extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    store.subscribe(this.handleUpdate.bind(this))
  }
  render() {
    return (
    //some codes
    )
  }
  handleUpdate() {
  	this.setState(store.getState())
 }
}
export default App;

我们先对加号进行操作, 对其绑定点击事件.

//App.js
<Button
  type="primary"
  onClick={this.handleAdd.bind(this)}
>
  +
</Button>

handleAdd() {
    const action = {
      type: 'add_number',
    }
    store.dispatch(action)
  }
function reducer(state = defaultState, action) {
  if (action.type === 'add_number') {
  	console.log('add_number')
    const newState = JSON.parse(JSON.stringify(state))
    newState.number += 1
    return newState
  }
  return state
}

在handleAdd中定义了action, 使用store.dispatch(action)来调度. 当执行dispatch时, 组件的state对象和action对象就会传到reducer中并执行reducer. 我们在reducer函数定义了action.type为’add_number’时的情况.
我们点击加号, 返现数字加1了.
redux的数据流
同理对于减号也是一样的.
这里我们直接将App.js的所有代码贴出来:

import React, { Component } from 'react';
import 'antd/dist/antd.css';
import { Button } from 'antd'
import { createStore } from 'redux'


//reducer
const defaultState = {
  number: 1
}
function reducer(state = defaultState, action) {
  if (action.type === 'add_number') {
    const newState = JSON.parse(JSON.stringify(state))
    newState.number += 1
    return newState
  }
  if (action.type === 'sub_number') {
    const newState = JSON.parse(JSON.stringify(state))
    newState.number -= 1
    return newState
  }
  return state
}

//store
const store = createStore(reducer)

class App extends Component {
  constructor(props) {
    super(props)
    this.state = store.getState()
    store.subscribe(this.handleUpdate.bind(this))
  }
  render() {
    return (
      <div>
        <div className="App" style={{marginLeft: '10px', marginBottom: '20px'}}>
          <div>{this.state.number}</div>
          <Button
            type="primary"
            onClick={this.handleAdd.bind(this)}
          >
            +
          </Button>
          <Button
            type="primary"
            onClick={this.handleSub.bind(this)}
          >
            -
          </Button>
        </div>
      </div>
    )
  }
  handleUpdate() {
    this.setState(store.getState())
  }
  handleAdd() {
    const action = {
      type: 'add_number',
    }
    store.dispatch(action)
  }
  handleSub() {
    const action = {
      type: 'sub_number',
    }
    store.dispatch(action)
  }
}

export default App;