您的当前位置:首页正文

Mobx在React中的应用

2024-11-08 来源:个人技术集锦

一、环境安装

1、首先使用 npm install mobx mobx-react 安装mobx和mobx-react
2、开通实验权限:experimentalDecorators: 解决办法:在项目根目录下创建一个jsconfig.json文件,然后加上
{
    "compilerOptions": {
        "experimentalDecorators": true
    }
}

3、解决Support for the experimental syntax 'decorators-legacy' isn't currently enabled (5:5): 报错。
第一步: 安装decorators:  npm install @babel/plugin-proposal-decorators;
第二步:在package.json中加入这句话:
"babel": {
    "plugins":[[
      "@babel/plugin-proposal-decorators",{
        "legacy":true
      }
    ]],
    "presets": [
      "react-app"
    ]
  }

二、Mobx的基础知识

mobx是使用状态管理库。建议大家看一下此大神的基础视频,有利于本文的理解
[慕课](https://www.imooc.com/learn/1012)

先来一个例子(后面会有介绍):

import { observable, action, computed } from "mobx";

class Todo {
  @observable title = "";
  @observable finished = false;

  constructor(title) {
    this.title = title;
  }
  @action.bound changeState() {
    this.finished = !this.finished;
  }
}

class Store {
  @observable todos = [];

  /**
   *
   * @param {删除} todo
   */
  @action.bound delete(todo) {
    this.todos.remove(todo);
  }

  /**
   * 得到非finished得长度
   */
  @computed get todoLength() {
    return this.todos.filter(value => !value.finished).length;
  }

  /**
   *
   * @param {添加一个todo} title
   */
  @action.bound addTodo(title) {
      
    this.todos.unshift(new Todo(title));
  }
}

export { Store, Todo };


Mobx的用法介绍:

  •  @observalbe:可以用来观测一个数据,这个数据可以数字、字符串、数组、对象等类型;
  •  @action: 动作是任何用来修改状态的东西。 action 装饰器/函数遵循 javascript 中标准的绑定规则。 但是,action.bound 可以用来自动地将动作绑定到目标对象
  •  @computed: 当状态发生变化时,自动得到一个计算值。
  •  @observer:可以观察可观察者的对象,可以接收到可观察者发生变化时候发出的消息,并且根据变化做出响应;也就是当observalue修饰的数据变化之后,会自动触发呗observer修饰的对象。

三、使用mobx显示列表数据

现在我们有这样一个需求,使用输入框,每次输入数据之后,按一下enter键,就在列表中添加一条数据,并且在底部显示出没有被选中的条目。点击每一项的删除键时候删除数据。同时更新头部,底部,和列表。

因为在一个项中删除会同步修改header,footer以及列表显示。那么久需要使用到Mobx的另一个特性:observer 用来说明哪些对象需要监听observable修饰的数据

效果图:

//先看整体
import React, { Component } from "react";
import { Store } from "./Store";
import { observer } from "mobx-react";
import "./index.css";

/**
 * 头部负责输入数据
 */

@observer
class HeaderInput extends Component {
 
}

/**
 * 底部负责显示当前未选中数据的个数
 */
@observer
class Footer extends Component {
 
}

/**
 * 列表项目的每一个
 */
@observer
class TodoItem extends Component {
  
}

/**
 * 显示整个列表
 */
@observer
class TodoView extends Component {
 
  
}

var store = new Store();

/**
 * 将列表,头部,底部结合起来
 */
@observer
class MobxDemo extends Component {
  render() {
    return (
      <div>
        <HeaderInput store={store} />

        <TodoView store={store} />
        <Footer shift={store.todoLength} />
      </div>
    );
  }
}

export default MobxDemo;


上述代码中使用mobx的observer特性,列表的显示分为头部,列表显示部分,底部。我们首先来看头部的逻辑。

头部的主要功能:在输入框中输入数据,当键盘按下enter的时候,触发之前使用@action修饰的addTodo 动作,这样状态中的数据就会增加一条。

/**
 * 头部负责输入数据
 */

@observer
class HeaderInput extends Component {
  state = { inputValue: "" };

  /**
   * 提交
   */
  onSubmit = e => {
    e.preventDefault();
    //store是是在MobxDemo中传入进来的,然后修改状态中的值
    this.props.store.addTodo(this.state.inputValue);

    console.log(this.state.inputValue);
    //添加之后要清空输入框的值
    this.setState({
      inputValue: ""
    });
  };

  /**
   * 监听输入框的输入
   */
  onInputChange = e => {
    var inputValue = e.target.value;
    this.setState({
      inputValue
    });
  };

  render() {
    return (
      <div>
        <form className="header-form" onSubmit={this.onSubmit}>
          <input
            className="header-input"
            onChange={this.onInputChange}
            value={this.state.inputValue}
            placeholder="Please input ...."
          />
        </form>
      </div>
    );
  }
}

然后我们再来看底部,底部的主要功能就是显示没有finished的项个数。没错就是这样简单,但是要记得有observer哦

/**
 * 底部负责显示当前未选中数据的个数
 */
@observer
class Footer extends Component {
  render() {
    return <div className="todo-footer">{this.props.shift + ", length"}</div>;
  }
}

然后我们可以来开始渲染列表咯,列表的渲染分为 列表整体的渲染和每一项的渲染。

/**
 * 列表项目的每一个,有一个复选框,和title
 */
@observer
class TodoItem extends Component {
  onChangeState = () => {
    this.props.todo.changeState();
  };
  render() {
    var { title, finished } = this.props.todo;
    return (
      <div className="todo-item-d">
        <input
          type="checkbox"
          checked={finished}
          onChange={this.onChangeState}
        />
        <span className={["title", finished && "delete"].join(" ")}>
          {title}
        </span>
      </div>
    );
  }
}

/**
 * 显示整个列表
 */
@observer
class TodoView extends Component {
  /**
   * 获取随机的颜色
   */
  getRandomColor = () => {
    return {
      backgroundColor: (function() {
        return "#" + Math.floor(Math.random() * 0xffffff).toString(16);
      })()
    };
  };

  render() {
  //获取到store中有哪些todo
    var store = this.props.store;
    var todos = store.todos;

    return todos.map((item, index) => {
      return (
        <li key={index} className="todo-item" style={this.getRandomColor()}>
          <TodoItem todo={item} />
       {/* 这是一个删除按钮,调用的是store中呗@action修饰过得删除动作 */}
          <span
            className="delete-item"
            onClick={() => {
              store.delete(item);
            }}
          >
            X
          </span>
        </li>
      );
    });
  }
}

显示全文