mobx实现todoList

2019-11-07  本文已影响0人  any_5637

在了解mobx的基础之后,今天写了一个小demo,实现todolist。

开发环境搭建

  1. 创建项目: npx create-react-app mobx-todo;
  2. 安装mobx相关依赖:npm install -S mobx mobx-react;
  3. 安装项目支持装饰器的依赖:
    npm run eject
    npm install --save-dev babel-plugin-transform-decorators-legacy
  4. 在根目录下创建.babelrc文件并写入:
  {
    "presets": ["@babel/preset-env"],
    "plugins": [
      ["@babel/plugin-proposal-decorators", { "legacy": true }],
      ["@babel/plugin-proposal-class-properties", { "loose": true }]
    ]
  }
  1. 启动服务器: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
上一篇 下一篇

猜你喜欢

热点阅读