redux的資料流
redux的data flow
redux是JavaScript的狀態容器, 通過redux, 我們可以輕鬆的對狀態進行管理. 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了. 同理對於減號也是一樣的. 這裡我們直接將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;