之前用redux改进了todolist,用redux对应用状态进行管理,今天换成mobx。
1. 在create-react-app中使用装饰器
- 使用react-app-rewired
yarn add customize-cra react-app-rewired @babel/plugin-proposal-decorators --save复制代码
- 项目根目录新建config-overrides.js文件加入以下代码
const { override, addDecoratorsLegacy } = require('customize-cra');module.exports = override( addDecoratorsLegacy() );复制代码
- 修改package.json文件如下
"scripts": { "start": "react-app-rewired start", "build": "react-app-rewired build", "test": "react-app-rewired test", "eject": "react-app-rewired eject" },复制代码
2. 了解mobx
可以先学习熟悉基本概念
- 按照上面改造create-react-app创建的项目后,引入mobx
yarn add mobx mobx-react复制代码
- 修改APP.js实现一个简单的domo
- @observable 可以在实例字段和属性 getter 上使用, 对于对象的哪部分需要成为可观察的
- @action 用来修改observables状态
- @computed可以根据现有的状态或其它计算值衍生出的值,可以在任意类属性的 getter 上使用 @computed 装饰器来声明式的创建计算属性
- @observer mobx与react结合的桥梁
import React from 'react';import ReactDOM from 'react-dom';import './index.css';// import App from './App';import * as serviceWorker from './serviceWorker';import {observable, action, computed} from 'mobx'import {observer} from 'mobx-react'class Store { @observable timer = 0 @computed get doubleTimer () { return this.timer * 2 } @action.bound add () { this.timer ++ }}@observerclass App extends React.Component { render () { const {doubleTimer, add} = this.props.store return ({doubleTimer}) }}ReactDOM.render(, document.getElementById('root'));// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://bit.ly/CRA-PWAserviceWorker.unregister();复制代码
3. 使用mobx管理todolist的状态
- 修改之前的项目,添加mobx相关包
yarn add mobx mobx-react复制代码
- 按照上面的步骤修改使其支持装饰器
- 新建store/index.js
import {observable, action} from 'mobx'import list from '../data'class Store { @observable todos = list @action addTodo = (todo) => { // 增 this.todos = [...this.todos, todo] } @action deleteTodo = (id) => { // 删 this.todos = this.todos.filter(item => { return item.id !== id }) } @action completeTodo = (id) => { // 改 this.todos = this.todos.map(item => { let obj = item.id === id ? {...item, isComplete: !item.isComplete} : item return obj }) } @action searchTodo = (content) => { // 查 if (content === '') { this.todos = list } else { this.todos = this.todos.filter(item => { return item.content.indexOf(content) !== -1 }) } }}export default new Store()复制代码
- 新建Provider组件作用和react-redux里面的Provider类似,父子组件之间通过context将store传递下去
import React, {Component} from 'react';import PropTypes from 'prop-types'export default class Provider extends Component { static propTypes = { store: PropTypes.object.isRequired, }; static childContextTypes = { store: PropTypes.object, }; getChildContext() { return { store: this.props.store } } render() { return this.props.children; }}复制代码
- 改造components/TodoItem.js
import React from 'react';import { Typography, Button } from 'antd';import PropTypes from 'prop-types'import {observer} from 'mobx-react'import './TodoItem.less'const { Text } = Typography;@observerclass TodoItem extends React.Component { static contextTypes = { store: PropTypes.object, }; render () { let { content, isComplete, id } = this.props let { completeTodo, deleteTodo } = this.context.store return (completeTodo(id)} style={ {cursor: 'pointer'}}>) }}export default TodoItem;复制代码{content}
- 改造components/DataList.js
import React from 'react';import {observer} from 'mobx-react'import TodoItem from './TodoItem'import PropTypes from 'prop-types'import { List } from 'antd';@observerclass DataList extends React.Component { static contextTypes = { store: PropTypes.object, }; render () { const {todos} = this.context.store return ((
)} /> ) }}export default DataList;复制代码
7.改造components/Form.js
import React from 'react';import {observer} from 'mobx-react'import PropTypes from 'prop-types'import { Input } from 'antd';const Search = Input.Search;@observerclass Form extends React.Component { static contextTypes = { store: PropTypes.object, }; render () { const {searchTodo} = this.context.store return (searchTodo(value)} enterButton /> ) }}export default Form;复制代码
- 改造componets/Footer.js
import React, { Component } from 'react';import {observer} from 'mobx-react'import { Button, Input } from 'antd';import PropTypes from 'prop-types'@observerclass Footer extends Component { static contextTypes = { store: PropTypes.object, }; constructor(props) { super(props) this.state = { isAdd: false, addTodo: {} } } handleClick () { this.setState({ isAdd: true }) } handleChange (e) { this.setState({ addTodo: { content: e.target.value, id: new Date(), completed: false } }) } handleConfirm () { this.context.store.addTodo(this.state.addTodo) this.setState({ isAdd: false }) } render () { let addBtn = let addComponent =this.handleChange(e)} style={ {marginRight: '10px'}}/>let component = this.state.isAdd ? addComponent : addBtn return ({component}) }}export default Footer;复制代码
- 将所有改过的组件都引入到todoList中
import React from 'react'import {observer} from 'mobx-react'import { Layout } from 'antd';import Form from './components/Form'import DataList from './components/DataList'import Footer from './components/Footer'import './todolist.less'import store from './store'import Provider from './components/Provider'const { Header, Content} = Layout;const TodoListApp = observer(() => { return (TodoList
重新运行yarn start,至此使用mobx对todolist改造完毕。
相关: