1. 程式人生 > >redux的資料流

redux的資料流

redux的data flow

redux是JavaScript的狀態容器, 通過redux, 我們可以輕鬆的對狀態進行管理. redux的data flow如下所示: redux-data-flow (圖片來源於慕課網) 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後顯示如下: 圖片

我想實現這樣一個需求, 當點選加號時, 數字加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了. add-number 同理對於減號也是一樣的. 這裡我們直接將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;