[置顶] React 项目中使用 MobX 进行状态管理
2018-02-24 09:54
806 查看
React 项目中使用 MobX 进行状态管理
说明
MobX 是一个简单的、可扩展的状态管理器,他通过透明的函数式编程使得状态管理变的简单和可扩展React 和 MobX 是一对强力组合。React 通过提供机制把应用状态转换为可渲染组件树并对其进行渲染。而 MobX 提供机制来存储和更新应用状态供 React 使用。
参考 MobX 中文文档
完整项目代码
概念
State 状态Derivations 衍生,源自状态,并且会不再有进一步相互作用的东西
Computed values 计算值,使用纯函数从当前可观察状态中衍生出的值
Reactions 反应,当状态改变时,需要自动发生的副作用
Actions 动作,任意一段可以改变状态的代码,尽量只在动作中修改状态
原则
MobX 中支持单项数据流,也就是动作改变状态,而状态的改变会更新所有受影响的视图状态改变时,所有衍生都会进行原子级的自动更新,因此不会观察到中间值
所有衍生默认都是同步更新,这意味着可以在改变状态之后更安全的检查计算值
计算值是延迟更新的,任何不在使用状态的计算值将不会更新
所有计算值都应该是纯净的,他们不应该用来改变状态
API
@observable一个装饰器,用于将对象的某一部分变成可观察的
@computed一个装饰器,计算值,根据现有状态或其他计算值衍生出的值
@computed.struct用于比较结构,设置为 true 时,表达式的输出在结果上与先前的值进行比较,然后通知观察者相关的更改
@computed.equals(comparer)用于自定义比较结构,comparer 是一个自定义比较函数,mobx 提供三个内置比较器 同过
import { comparer } from 'mobx'得到
comparer.default等
Autorun当需要创建一个响应式函数,但是函数本省并不需要观察者时,可以使用此 api,与
computed相同点是都会响应依赖的变化,不同点是
computed会返回一个新的值,用作
de22
观察者观察,而
autorun没有观察者,他只是响应变化后执行一段代码
@observer由
mobx-react提供的装饰器,用来将 react 组件转换为响应式的组件,需要确保
observer是最深处(第一个应用)
Provider组件,由
mobx-react提供,它使用了 react 的上下文(context)机制,可以用来向下传递
stores
@inject()将组件链接到
stores,需要传递一个 stores 名称的列表给
inject使得 stores 可以作为组件的 props 使用
componentWillReact声明周期钩子,当组件因为它观察的数据发生变化,他会被安排重新渲染,这个时候
componentWillReact钩子会被触发
action动作,动作是用来修改状态的
完整案例代码
1. /index.js
入口文件
/* 项目入口 */ import './scss/index.scss'; import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import { useStrict } from 'mobx'; import { Provider } from 'mobx-react'; import Root from './router/routes'; import stores from './store/index'; const mountNode = document.getElementById('app'); useStrict(true); const render = (Component, stores) => { // 卸载掉旧的组件 ReactDOM.unmountComponentAtNode(mountNode); // 重新渲染新的组件 ReactDOM.render( <Provider {...stores}> <BrowserRouter> <Component /> </BrowserRouter> </Provider>, mountNode ); }; render(Root, stores); /* 这里的热更新只监视 store 部分代码变化,然后进行重新渲染组件, 组件的热更新还是交给 react-hot-loader 组件处理(route文件中) */ if (module.hot) { module.hot.accept('./store/index.js', () => { console.log('mobx changed'); render( require('./router/routes.js').default, require('./store/index.js').default ); }); }
2. /store/index.js
store 状态集合
/* 合并后的 store */ import app from './modules/app'; import member from './modules/member'; const stores = { app, member }; export default stores;
3. /store/modules/members.js
每一个页面的子 store
/* 成员列表页 */ import { observable, computed, action } from 'mobx'; // 将获取数据部分分离出去 import { obtainMemberList, postNewMember, deleteMember } from '../../api/members'; class MemberStore { // 将需要观察的属性设置为可观察的 @observable members; @observable filter; // 在这里给可观察的属性设置初始值 constructor() { this.members = []; this.filter = ''; } // 计算属性 @computed get filtedMembers() { const members = [...this.members]; if (this.filter === '') { return members; } const filterReg = new RegExp(this.filter, 'g'); return members.filter( ({ name, tel }) => filterReg.test(name) || filterReg.test(tel) ); } // 动作,代码专注于更新可观察属性,额外的操作分离出去 @action changeMembers = members => { this.members = members; }; @action changeFilter = newFilter => { this.filter = newFilter; }; /* 一些函数,包含更新可观察属性的部分已经被分离为 action 在 action 中使用异步函数或者 promise 都比较麻烦,所以尽可能的分离, 据文档指出,不但 异步函数需要被 @action await 后的代码如果更改了可观察属性,需要使用 runInAction 包裹 */ getMembers = async () => { const members = await obtainMemberList(); this.changeMembers(members); }; postMember = async newMember => { await postNewMember(newMember); await this.getMembers(); }; deleteMember = async memberId => { await deleteMember(memberId); await this.getMembers(); }; } // 返回一个实例 export default new MemberStore();
4. /container/Member.js
容器组件
/* 成员列表 */ import React, { Component } from 'react'; import { inject, observer } from 'mobx-react'; import MemberCom from '../components/member/index'; @inject('member') // 给组件注入其需要的 store,指定对应的子 store 名称 @observer // 将组件转化为响应式组件 export default class Member extends Component { constructor(props) { super(props); } render() { const { member } = this.props; return <MemberCom member={member} />; } }
5. /components/member/index.js
展示组件
/* MemberCom */ import React, { Component } from 'react'; import { observer } from 'mobx-react'; import Toolbar from './Toolbar'; import MemberList from './MemberList'; import './member.scss'; /* 这里有个坑,只要子组件使用了 store 中的可观察属性, 就需要通过 @observer 将其变成响应式组件 */ @observer export default class MemberCom extends Component { constructor(props) { super(props); } render() { const { filtedMembers, filter, postMember, deleteMember, changeFilter } = this.props.member; return ( <div id="member-container"> <Toolbar filter={filter} postMember={postMember} changeFilter={changeFilter} /> <MemberList filtedMembers={filtedMembers} deleteMember={deleteMember} /> </div> ); } componentWillMount() { const { getMembers } = this.props.member; getMembers(); // 请求获取初始数据 } }
相关文章推荐
- 使用 IBM Rational RequisitePro 进行项目执行管理
- 使用autotools进行项目管理简单应用
- 使用trac进行项目管理
- 使用Project客户端和Project Server进行项目管理
- 怎么使用Team Foundation Server 2010(TFS)和Project 2010进行软件开发项目管理(一)
- 使用 JIRA 4.0 + Greenhopper 4.0 进行项目状态跟踪(转)
- vs.net web项目使用visual source safe进行源代码管理
- vs.net web项目使用visual source safe进行源代码管理
- 使用trac系统进行项目管理
- 使用googlecode进行项目管理(Linux)
- 使用EVM进行项目管理时的注意事项
- ASP.NET项目怎样进行管理?(VSS的使用)
- 使用Project客户端和Project Server进行项目管理
- (摘)vs.net web项目使用visual source safe进行源代码管理
- 使用CVS进行项目开发管理
- 使用trac进行项目管理
- 使用STARTEAM进行项目管理
- 使用SVN进行项目版本管理
- vs.net web项目使用visual source safe进行源代码管理
- 使用Project客户端和Project Server进行项目管理