在了解mobx的基础之后,今天写了一个小demo,实现todolist。
开发环境搭建
- 创建项目:
npx create-react-app mobx-todo
; - 安装mobx相关依赖:
npm install -S mobx mobx-react
; - 安装项目支持装饰器的依赖:
npm run eject
npm install --save-dev babel-plugin-transform-decorators-legacy
- 在根目录下创建.babelrc文件并写入:
{
"presets": ["@babel/preset-env"],
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
]
}
- 启动服务器:
npm run start
。
创建mobx状态管理store
在根目录下创建文件夹stores,新建store.js文件,声明一个类todoList,给其创建属性:todos,使用@observable让其变为可观察对象,其中操作的过程就不细说,先上代码:
import {observable, action, computed, toJS} from 'mobx';
class todoList {
@observable todos = [
{
id: parseInt(Math.random() * 10000000),
isComplete: false,
title: 'ddd'
},
{
id: parseInt(Math.random() * 10000000),
isComplete: true,
title: 'ddd'
}
];
// 计算属性,重可观察属性 todos 衍生出来,返回没有完成的待办项的个数
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.isComplete).length;
}
// 计算属性,重可观察属性 todos 衍生出来,返回已完成的待办项的个数
@computed get finishedTodoCount() {
return this.todos.filter(todo => todo.isComplete).length;
}
@action
toggleComplete = (val) => {
const todos = toJS(this.todos).map(item => {
if(item.id == val) {
item.isComplete=true;
}
return item;
});
this.todos = todos;
}
@action
toggleTodo = (val) => {
const todos = toJS(this.todos).map(item => {
if(item.id == val) {
item.isComplete=false;
}
return item;
});
this.todos = todos;
}
@action
AddTodo = (val) => {
const todo = this.todos;
this.todos = [val, ...todo];
}
@action
deletes = (val) => {
const todos = toJS(this.todos).filter(item => item.id != val);
this.todos = todos;
}
}
const store = new todoList();
export default store;
实现监听数据的组件
Provider、observer、inject均为是mobx-react提供。
Provider以组件的形式存在,用来包裹最外层组件节点,并且传入 store(通过)context 传递给后代组件。
使用@observer装饰的react组件将转换成一个监听者,当@observable 修饰的数据变化,react组件就会重新渲染。
@inject为了使被装饰的组件以 props 的形式获取到 Provider 传递过来的数据。
新建三个组件AddTodo.js Done.js Todo.js,在组件中使用this.props获得父组件的stores数据。
AddTodo组件:新增待办事项
import React from 'react';
import {observer, inject} from 'mobx-react';
import './AddTodo.css';
@inject('appState')
@observer
export default class AddTodo extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '', // 定义新增事项的输入框的值
}
}
// 监听输入框的值
handleInput(e) {
this.setState({
input: e.target.value
})
}
// 确认新增,调用store的动作,新增数据
handleClick(e) {
this.props.appState.AddTodo({
id: parseInt(Math.random() * 10000000),
isComplete: false,
title: this.state.input
});
this.setState({
input: ''
}); // 清空输入框数据
}
render() {
return (
<div className='input-box'>
<input value={this.state.input} onChange={(e)=>this.handleInput(e)}></input><button onClick={(e)=>this.handleClick(e)}>确认</button>
</div>
)
}
}
Todo组件:展示正在进行的事项
import React, { Component } from 'react';
import {observer, inject} from 'mobx-react';
import './Todo.css';
@inject('appState')
@observer
export default class Todo extends Component {
constructor(props) {
super(props);
}
// 改变事项的状态为已完成
todoChange = (event) => {
//当onChange事件发生时,调用toggleComplete动作
this.props.appState.toggleComplete(event.target.value);
}
//取得未完成的todo数量
// getUnfinishedCount() {
// return this.props.appState.todos.filter((i) => {
// return i.isComplete === false;
// }).length;
// }
// 删除数据
deletee = (event) => {
this.props.appState.deletes(event.target.getAttribute("data-id"));
}
getTodos() {
return this.props.appState.todos.map((todo, index) => {
if(todo.isComplete == false) {
return (<li key={index} className='ulli'>
<input type="checkbox" value={todo.id} checked={todo.isComplete} onChange={this.todoChange}/>
<span>{todo.title}</span>
<button type="button" data-id={todo.id} onClick={this.deletee}>删除</button>
</li>)
}
});
}
render() {
console.log( this.props.appState.todos)
return (<div className='ising'>
<h5>正在进行<span className='ingspan'>{this.props.appState.unfinishedTodoCount}</span></h5>
<ul className='ullist'>
{this.getTodos()}
</ul>
</div>);
}
}
Done组件:展示已完成的事项
import React from 'react';
import {observer, inject} from 'mobx-react';
@inject('appState')
@observer
export default class Done extends React.Component {
constructor(props) {
super(props);
}
todoChange = (event) => {
this.props.appState.toggleTodo(event.target.value);
}
//取得已经完成的todo数量
// getUnfinishedCount() {
// //this.props.todos就是从connect传入的state数据
// return this.props.appState.todos.filter((i) => {
// return i.isComplete === true;
// }).length;
// }
// 删除已完成事项
delete = (event) => {
this.props.appState.deletes(event.target.getAttribute("data-id"))
}
getTodos() {
return this.props.appState.todos.map((todo, index) => {
if(todo.isComplete == true) {
return (<li key={index} className='ulli'>
<input type="checkbox" value={todo.id} checked={todo.isComplete} onChange={this.todoChange}/>
<del>{todo.title}</del>
<button type="button" data-id={todo.id} onClick={this.delete}>删除</button>
</li>)
}
});
}
render() {
return (<div className='ising'>
<h5>已经完成<span className='ingspan'>{this.props.appState.finishedTodoCount}</span></h5>
<ul className='ullist'>
{this.getTodos()}
</ul>
</div>);
}
}
通过 Provider 将数据传递给组件树
在app.js中,引入store,并通过Provider酱紫组件包裹,把store的数据传给子组件。
import React from 'react';
import ReactDOM from 'react-dom';
import './App.css';
import Todo from './views/Todo.js';
import AddTodo from './views/AddTodo.js';
import Done from './views/Done.js';
import store from './stores/store.js';
import {Provider} from 'mobx-react';
ReactDOM.render(
<div className='box'>
<Provider appState={store}>
<AddTodo></AddTodo>
<Todo></Todo>
<Done></Done>
</Provider>
</div>,
document.getElementById('app')
);
实现效果:
20191107_134916.gif
网友评论