Мобкс такой простой

внешний интерфейс MobX

В этой статье объясняется: mobx v5.0.0^, некоторые основные понятия mobx, советы по использованию mobx и совместному реагированию, моменты, на которые следует обратить внимание при использовании mobx.

  • что такое мобкс? Зачем развивать эту библиотеку?
  • Некоторые ключевые концептуальные связи в mobx: действия, состояние, вычисляемые значения, реакция.
  • Некоторые API, обычно используемые mobx: @observable, @autorun, @when, @computed, @action.
  • Инструменты для отладки трейсов в mobx
  • Что стоит отметить в mobx

Что такое Мобкс?

Это простое, масштабируемое управление состоянием. Потому что управление состоянием стало простым и расширяемым за счет прозрачного применения функционального реактивного программирования (TFRP).

Каковы основные понятия?

  • действия: Некоторые действия, которые изменяют значение состояния.
  • состояние: наблюдаемое значение состояния
  • вычисленное значение: в соответствии с состоянием значение, рассчитанное чистой функцией
  • Реакции: реакции, вызванные изменениями состояния или вычисляемого значения, в основном относящиеся к повторному рендерингу пользовательского интерфейса.

Общие декораторы

  • @observable делает переменную наблюдаемой
  • @observer часто используется в компонентах React для мониторинга наблюдаемых переменных, используемых в его функции рендеринга, для выполнения соответствующих реакций.
  • @autorun часто используется в конструкторе класса компонента или класса хранилища.При создании экземпляра он может отслеживать наблюдаемые переменные, используемые в параметрах его функции, чтобы выполнять соответствующие реакции, обычно выполняя функцию снова.
  • @когда условный @автозапуск
  • @computed Значение, вычисляемое чистой функцией через наблюдаемую переменную, оно будет вычисляться, когда оно используется, и не будет вычисляться, когда оно не используется.
  • @action Действие, которое может изменить значение наблюдаемой переменной (обычно метод функции)

Если вы не привыкли использовать декораторы, вы также можете использовать некоторые общие методы функций.В этой статье написаны только лучшие практики, которые я лично считаю, но которые будут отработаны, когда проект будет реализован позже.

Сравнение реализации проекта TodoList:GitHub.com/Пейдун Гу О/…

Группа 1: Вы когда-нибудь использовали Mobx?

// 无 mobx
class TodoList extends Component {
 state = { //组件数据只能在state里,更改只能用setState()
    inputItem: "",
    listFlag: "all",
    allList: []
  };

  handleInputItem = e => {
    this.setState({
      inputItem: e.target.value
    });
  };

  handleItemStatus = (e, index) => {
    e.persist();
    let items = this.state.allList;
    console.log(items, index);
    items[index].isCompleted = e.target.checked;
    this.setState({
      allList: items
    });
  };
  ...
  render(){
    ...
    <input
                className="new-todo"
                placeholder="What needs to be done?"
                value={this.state.inputItem}
                onChange={this.handleInputItem}
                onKeyDown={this.handleAddItem}
                autoFocus={true}
              />
    ...
     <li
                        className={item.isCompleted ? "completed" : ""}
                        className={item.isEditing ? "editing" : ""}
                        key={index}
                        onDoubleClick={() => {
                          this.handleItemEdit(index, true);
                        }}
                      >
                        <div className="view">
                          <input
                            className="toggle"
                            type="checkbox"
                            checked={item.isCompleted}
                            onChange={e => {
                              this.handleItemStatus(e, index);
                            }}
                          />
                          <label>{item.title}</label>
                          <button
                            className="destroy"
                            onClick={() => {
                              this.handleItemDelete(index);
                            }}
                          />
                        </div>
                        <input
                          className="edit"
                          value={item.title}
                          onChange={e => {
                            this.handleItemTitle(e, index);
                          }}
                          onBlur={e => {
                            this.handleItemEdit(index, false);
                          }}
                        />
                      </li>
    ...
  }
  ...
  }
// 有 mobx 而且使用装饰器语法
@observer  // 将组件变得可观察
class TodoListMobx extends Component {
  @observable inputItem = "";  // 将属性变成可观察属性
  @observable listFlag = "all";
  @observable allList = [];

  @action // 此操作会引起可观察属性的变化
  handleInputItem = e => {
    console.log(e.target);
    this.inputItem = e.target.value; // 直接修改可观察属性
    console.log(this.inputItem);
  };

  @action
  handleItemToggle = (e, index) => {
    e.persist();
    this.allList[index].isCompleted = e.target.checked;
  };
  ...
  render(){  // 可观察的组件当其包含的可观察属性变化后,render会再次执行。
      ...
      <li
                        className={LiClass}
                        key={index}
                        onDoubleClick={() => {
                          item.isEdit = true;
                        }}
                      >
                        <div className="view">
                          <input
                            className="toggle"
                            type="checkbox"
                            checked={item.isCompleted}
                            onChange={e => {
                              item.isCompleted = !item.isCompleted;
                            }}
                          />
                          <label>{item.title}</label>
                          <button
                            className="destroy"
                            onClick={e => {
                              this.handleItemDelete(index);
                            }}
                          />
                        </div>
                        <input
                          className="edit"
                          value={item.title}
                          onChange={e => {
                            item.title = e.target.value;
                          }}
                          onBlur={e => {
                            item.isEdit = false;
                          }}
                        />
                      </li>
    ...
  }
  ...
 }

Можно увидеть сравнение двух приведенных выше наборов кодов: добавление mobx упрощает операцию изменения данных в компоненте реакции и делает пользовательский интерфейс моторизованным. Более того, код в целом намного проще написать и легче понять.

Вторая группа: использовать декораторы или нет

Код, использующий декоратор, по-прежнему относится ко второму блоку кода в первой группе.

// 有 mobx 而且 不使用装饰器语法

class TodoListMobxNoDeco extends Component {
  inputItem = "";  
  listFlag = "all";
  allList = [];

 
  handleInputItem = e => {
    console.log(e.target);
    this.inputItem = e.target.value; 
    console.log(this.inputItem);
  };

  
  handleItemToggle = (e, index) => {
    e.persist();
    this.allList[index].isCompleted = e.target.checked;
  };
  ...
  render(){  // 可观察的组件当其包含的可观察属性变化后,render会再次执行。
      ...
      <li
                        className={LiClass}
                        key={index}
                        onDoubleClick={() => {
                          item.isEdit = true;
                        }}
                      >
                        <div className="view">
                          <input
                            className="toggle"
                            type="checkbox"
                            checked={item.isCompleted}
                            onChange={e => {
                              item.isCompleted = !item.isCompleted;
                            }}
                          />
                          <label>{item.title}</label>
                          <button
                            className="destroy"
                            onClick={e => {
                              this.handleItemDelete(index);
                            }}
                          />
                        </div>
                        <input
                          className="edit"
                          value={item.title}
                          onChange={e => {
                            item.title = e.target.value;
                          }}
                          onBlur={e => {
                            item.isEdit = false;
                          }}
                        />
                      </li>
    ...
  }
  ...
 }
 decorate(TodoListMobxNoDeco, {
  inputItem: observable,
  allList: observable,
  listFlag: observable,
  handleAddItem: action,
  handleClearCompleted: action,
  handleInputItem: action,
  handleItemDelete: action,
  handleItemToggle: action,
  handleListChg: action
});

TodoListMobxNoDeco = observer(TodoListMobxNoDeco);

export default TodoListMobxNoDeco;

Если вы сможете сравнить этот набор примеров, то обнаружите, что декоратор — это просто синтаксический сахар, который можно сделать и без его использования, но после его использования код можно сделать намного чище.

Некоторые общие функции инструмента трассировки отладки будут использоваться в следующем практическом занятии.

  1. trace
  2. mobx-react-devtools
  3. spy

Помните следующие пункты

  • mobx отслеживает только ссылку на свойство observables, а не его значение
import DevTools from "mobx-react-devtools";
...
render(){return (
    <div>
        <DevTools />
    </div>
)}
...

//Counter组件,简单展示
@observer
class Counter extends Component {
  @observable count = 0; // 将count变成可观察属性

  countCopy = this.count;  // 被赋值给一个本地变量,不会随着this.count的变化而变化

  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        <span>这是 @observable 变量 count:{this.count}</span>
        <br />
        <span>这是 @observable 变量 count的本地拷贝:{this.countCopy}</span>
        <br />
        <span onClick={this.handleAdd}>Count加一</span>
        <br />
        <span onClick={this.handleDec}>Count减一</span>
      </div>
    );
  }

  @action
  handleAdd = () => {
    this.count++;
  };

  @action
  handleDec = () => {
    this.count--;
  };
}

Вы видите, что скопированные переменные не изменятся.

  • Обращайтесь к подсвойствам свойства observables как можно позже
// 这个例子中,父组件在使用子组件时直接赋值了整个observable,导到如果此Observable地址不变,子组件极有可能不会重新渲染

class SubCounter extends Component {
  render() {
   const count=this.props.count;
    return (
      <div>
        <span>
          这是子组件显示父组件 @observable 变量 countObj.count1:
          {count.count1}
        </span>
        <br />
        <span>
          这是子组件显示父组件 @observable 变量 countObj.count1:
          {count.count2}
        </span>
      </div>
    );
  }
}

@observer
class Counter extends Component {
  @observable count = 0;

  countCopy = this.count;

  @observable countObj = {
    count1: 1,
    count2: 2
  };

  constructor(props) {
    super(props);
  }
  render() {
    const countCopy2 = this.count;
    return (
      <div>
       // 这里直接引用了整个observable,导到如果此Observable地址不变,子组件极有可能不会重新渲染
        <SubCounter count={this.countObj} /> 
        <span>
          这是 @observable 变量 countObj.count2:{this.countObj.count2}
        </span>
        <br />
        <span>这是 @observable 变量 count的本地拷贝:{this.countCopy}</span>
        <br />
        <span onClick={this.handleAdd}>CountObj.count1加一</span>
        <br />
        <span onClick={this.handleDec}>Count减一</span>
      </div>
    );
  }

  @action
  handleAdd = () => {
    this.countObj.count1++;
  };

  @action
  handleDec = () => {
    this.count--;
  };
}
export default Counter;
  • Вложенные компоненты предпочтительно являются наблюдателями на каждом уровне.
@observer //如果注掉,那么不会监视传过来的count, 自然不会重新渲染
class SubCounter extends Component {
  render() {
    return (
      <div>
        <span>
          这是子组件显示父组件 @observable 变量 countObj.count1:
          {this.props.count.count1}
        </span>
        <br />
        <span>
          这是子组件显示父组件 @observable 变量 countObj.count1:
          {this.props.count.count2}
        </span>
      </div>
    );
  }
}

@observer
class Counter extends Component {
  @observable count = 0;

  countCopy = this.count;

  @observable countObj = {
    count1: 1,
    count2: 2
  };

  constructor(props) {
    super(props);
  }
  render() {
    const countCopy2 = this.count;
    return (
      <div>
        <SubCounter count={this.countObj} />
        <span>
          这是 @observable 变量 countObj.count2:{this.countObj.count2}
        </span>
        <br />
        <span>这是 @observable 变量 count的本地拷贝:{this.countCopy}</span>
        <br />
        <span onClick={this.handleAdd}>CountObj.count1加一</span>
        <br />
        <span onClick={this.handleDec}>Count减一</span>
      </div>
    );
  }

  @action
  handleAdd = () => {
    this.countObj.count1++;
  };

  @action
  handleDec = () => {
    this.count--;
  };
}
export default Counter;