react中的状态管理有很多,我们今天讲的是react-redux 和 mobx。
一:mobx
1、根目录
index.js
import { Provider } from 'mobx-react'
ReactDOM.render(<Provider locale={zh_CN}><App store={AppStore} /></Provider>, document.getElementById('root'))
app.js
import { Provider } from 'mobx-react'
render() {
//const newState = new AppStore()
return (
<Provider {...this.props}>
<BrowserRouter history={history} basename="/">
<div className="App">
{/* <TopView /> */}
<div className="mainContain">
<RouterConfig />
</div>
</div>
</BrowserRouter>
</Provider>
)
}
2、appStore文件
import { observable, computed, action } from 'mobx';
@observable:值可以是JS基本数据类型、引用类型、普通对象、类实例、数组和映射。其修饰的state会暴露出来供观察者使用
@observable
接受任何类型的 js 值(原始类型、引用、纯对象、类实例、数组和、maps),observable 的属性值在其变化的时候 mobx 会自动追踪并作出响应。
当 value 是一个对象类型值的时候,它会默认克隆该对象并且把其中每个属性变为可观察的值,这里默认是深拷贝,也就是说其对象的后代属性都会变成可观察的,比如 @observable classProperty = { obj: { name: 'q' } }
,当 classProperty.obj.name
改变的时候,在 MobX 中也是可以观察到并响应的;
当然在这里可以加一些调节器来做一些配置:
- @observable.deep (默认)对对象进行深拷贝;
- @observable.shallow 它只对对象进行浅拷贝;
- @observable.ref 禁用对象的自动转化,只转化其引用;
@action:只有在 actions 中,才可以修改 Mobx 中 state 的值,支持异步
注意:当你使用装饰器模式时,@action 中的 this 没有绑定在当前这个实例上,要用过 @action.bound 来绑定 使得 this 绑定在实例对象上。
@computed get TodoListCount() {
return this.todos.length;
}
autorun
在上面的例子中,当触发了可观察状态属性的改变后,其变化的监听则是在传入 autorun 函数中作出响应。
autorun 接受一个函数作为参数,在使用 autorun 的时候,该函数会被立即调用一次,之后当该函数中依赖的可观察状态属性(或者计算属性)发生变化的时候,该函数会被调用,注意,该函数的调用取决的函数中使用了哪些可观察状态属性(或者计算属性)。
componentDidMount() {
const { store } = this.props
var that = this
autorun(() => {
console.log('11', store.name)
that.setState({
numbers: store.name
})
})
}
3、组件中引入:
import { observer, inject } from 'mobx-react'
@inject('store')
@observer
//获取store
const { store } = this.props
store.setWarnFlag(false)
class appStore {
@observable socketUrl = 'kc.tianren.com:6060/ws'
@action setSocketUrl(socketUrl) {
this.socketUrl = parseInt(socketUrl)
}
@observable nowIndex = 0
@observable childNowIndex = 5
@action setIndex(nowIndex) {
this.nowIndex = parseInt(nowIndex)
}
@action setChildIndex(childNowIndex) {
this.childNowIndex = parseInt(childNowIndex)
}
@observable flag = false
@action setFlag(flag) {
this.flag = flag
}
@observable warnFlag = true
@action setWarnFlag(warnFlag) {
this.warnFlag = warnFlag
}
@observable todos = [
{
name: `李四`,
age: 1
}
] //todos列表
@action fetchTodos() {
var randomAge = Math.random(10)
this.todos.push({
name: `张三${randomAge}`,
age: randomAge
})
}
@action fetchTodoRemove() {
this.todos.pop()
}
//添加
@action AddTodo = () => {
this.fetchTodos()
}
//删除单个
@action remove() {
this.fetchTodoRemove()
}
//计算长度
@computed get TodoListCount() {
return this.todos.length
}
}
const AppStore = new appStore()
export default AppStore
二:Redux
index.js//
import { Provider } from 'react-redux'
import { createStore } from 'redux';
import testReducer from './store/reducer'
const store = createStore(testReducer)
Home.js//
import { connect } from "react-redux"
import { setName, getName, resetName } from '../store/actions'
setA(name) {
console.log('sss')
this.props.setName(name)
}
function mapStateToProps(state) {
return {
name: state.name
};
}
const mapDispatchToProps = {
setName,
getName,
resetName
};
export default connect(mapStateToProps, mapDispatchToProps)(Home)
reduce //
import { SET_NAME, GET_NAME, RESET_NAME } from './actions'
const finialState = {
name: '未设置'
};
export default function testReducer(state = finialState, actions) {
switch (actions.type) {
case GET_NAME:
return {
name: `my name is ${state.name}`
}
case SET_NAME:
return {
name: actions.preload.value
}
case RESET_NAME:
return {
name: '未设置'
}
default:
return state;
}
}
//rootReducer
import { combineReducers } from "redux";
export default combineReducers({
products
});
同样注意 Redux 如何传递了一个 undefined 的 state,同时 action 是一个有 type 属性的对象。
我们稍后会更多地讨论 actions。现在,我们先看看 reducer。
记住 reducer 的职责是接收当前 state 和一个 action 然后返回新的 state。
const initialState = {
count: 0
};
function reducer(state = initialState, action) {
console.log('reducer', state, action);
return state;
}
Actions 的格式非常自由。只要它是个带有 type 属性的对象就可以了。
另一个关于 reducers 的规则是它们必须是纯函数。也就是说不能修改它们的参数,也不能有副作用(side effect)。必须返回一个 state,不要改变 state
const store = createStore(reducer);
store.dispatch({ type: "INCREMENT" });
要做到这一点,要用到 react-redux 库的两样东西:一个名为 Provider 的组件和一个 connect 函数。
function mapStateToProps(state) {
return {
count: state.count
};}
export default connect(mapStateToProps)(Counter);
这样写是因为 connect 是一个高阶函数,它简单说就是当你调用它时会返回一个函数。然后调用返回的函数传入一个组件时,它会返回一个新(包装的)组件。
固执的 Redux 只接受简单对象作为 actions。
“thunk” 是(少见)指被其它函数作为返回值的函数。你可以像其他 action 生成器一样 dispatch 这些 “thunk actions”:dispatch(getUser())。
function doStuff() {
return function(dispatch, getState) {
// 在这里 dispatch actions
// 或者获取数据
// 或者该干啥干啥
}}
Action 生成器返回的函数接收两个参数:dispatch 函数和 getState。
大多数场景你只需要 dispatch,但有时你想根据 Redux state 里面的值额外做些事情。这种情况下,调用 getState() 你就会获得整个 state 的值然后按需所取。
export function fetchProducts() {
return dispatch => {
dispatch(fetchProductsBegin());
return fetch("/products")
.then(res => res.json())
.then(json => {
dispatch(fetchProductsSuccess(json.products));
return json.products;
})
.catch(error => dispatch(fetchProductsFailure(error)));
};
}