前言:redux和mobx都是狀态管理器,避免父級到子級再到子子級嵌套單向資料流,可以邏輯清晰的管理更新共享資料。(重新整理頁面redux儲蓄資料即消失)
配置使用裝飾器(使用高階函數包裝你的元件):
npm install babel-plugin-transform-decorators-legacy --save-dev
.babelrc配置:
{
"presets": [
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"style": true
}
],
"transform-decorators-legacy"
]
}
當使用react native的時候,下面這個預設可以代替 transform-decorators-legacy
"babel": {
"presets": [
"react-app",
"react-native-stage-0/decorator-support"
]
},
一.redux
redux.js檔案:
// 定義變量
const CODE_CHANGE = 'CODE_CHANGE'
const NUMBER_LIST = 'NUMBER_LIST'
const ERROR_MSG = 'ERROR_MSG'
// 初始化資料
const initState = {
industryNumber: storage.get('industryNumber'),
numberList: [],
msg: ''
}
// reducer
export function isNumber(state = initState, action) {
switch (action.type) {
case CODE_CHANGE:
return { ...state, industryNumber: action.industryNumber }
case NUMBER_LIST:
return { ...state, numberList: action.numberList }
case ERROR_MSG:
return { ...state, msg: action.msg }
default:
return state
}
}
reducer.js檔案:
import { combineReducers } from 'redux'
import { isNumber } from '/redux'
export default combineReducers({ isNumber }) // 合并所有的reducer,并且傳回
index.js入口檔案:
import React from 'react'
import ReactDOM from 'react-dom'
import MainRouter from './Router'
// 引入redux
import { createStore, applyMiddleware, compose } from 'redux'
importthunk from 'redux-thunk' // 中間插件,增強dispatch功能,可異步加載action可接受函數參數
import { Provider } from 'react-redux' //redux元件,全部子級可以直接更新redux的state
import reducers from './reducer'
// 這裡判斷浏覽器環境是否開啟Redux DevTools的插件(chrome浏覽器擴充插件應用商店下載下傳)
const reduxDevtools = window.devToolsExtension ? window.devToolsExtension() : h => h //沒有插件則傳回空函數
const store = createStore(reducers, compose( applyMiddleware(thunk), reduxDevtools )) // 建立store
ReactDOM.render(
<Provider store={store}>
<MainRouter/> //路由
</Provider>,
document.getElementById('root')
)
某子元件:
import { connect } from 'react-redux' // 裝飾器
const fetchNumberList = () => {
return dispatch => { // 異步請求需要 dispatch => {}包裹
fetch('異步請求').then(res => {
if (res.code === 0) {
dispatch({ type: 'NUMBER_LIST', numberList: res.data })
}
})
}
}
@connect(
state => state.isNumber, // 如果有多個reducer: state => ({ ..state.isNumber, ...state.someName })
{ fetchNumberList } // 一些之前寫好的action方法
)
class IndustryManagement extends Component {
constructor(props) {
super(props)
this.state= {
industryNumber: this.props.industryNumber && this.props.industryNumber[0], // 直接props引用redux的state
}
}
btnChange() {
this.props.fetchNumberList() //經過裝飾器的函數都可用props引用
}
render() {
return (
<button onClick={ this.btnChange.bind(this) }>
)
}
}
二. mobx
這裡推薦使用mobx-state-tree的寫法,有興趣的可去github上看用法,以下是傳統寫法:
store.js檔案:
import { observable, action, runInAction } from 'mobx'
// runInAction接受異步action
class RootStore {
@observable userInfo = null //注冊變量并監視變化(可以是引用類型值或者普通值)
@observable number1 = 1
@observable number2 = 2
@computed getTotal(){
return this.number1 + this.number2 // 每當監視資料發生變化就會執行@computed
}
@action.bound getData= async() => { // bound是為了綁定this上下文(箭頭函數可不需要)
let res = await get('接口位址')
if (res.success) {
runInAction(() => { // runInAction函數可異步修改@observable資料
this.userInfo = res.data
})
}
}
}
export default rootStore = new RootStore()
import { Provider } from 'mobx-react' // 與上文的redux的Provider相似
import rootStore from './store'
ReactDOM.render(
<Provider rootStore={rootStore}>
<MainRouter />
</Provider>,
document.getElementById('root')
)
import { observer, inject } from 'mobx-react'
@inject(({store, otherStore}) => ({ // 選擇注入store(如果有多個store),如果不用inject函數可直接import store from '../store',元件中直接store.userInfo使用
userInfo: store.userInfo,
total: store.getTotal
}))
@observer
class EmpRec extends Component {
constructor(props) {
super(props)
}
render() {
return(
<div>
<div>this.props.userInfo</div>
<div>this.props.total</div>
</div>
)
}
}