Mobx: class+makeObservable形式 和 observable()形式 混用的情景测试

40 阅读3分钟

基础文件:

  • store/class-a.js
// store/class-a.js
import { makeObservable, observable, action } from "mobx";
class classA {
  todos = [
    {
      id: 1,
      name: "Todo 1",
      completed: false,
      assignee: null
    }
  ]

  constructor() {
    makeObservable(this, {
      todos: observable,
      addTodo: action.bound,
      subTodo: action.bound,
      setTodoAssignee: action.bound,
    });
  }

  addTodo(todo) {
    this.todos.push(todo);
  }

  subTodo (index) {
    this.todos.splice(index, 1);
  }

  setTodoAssignee (todoIndex, assignee) {
    this.todos[todoIndex].assignee = assignee;
  } 
}

export default new classA();
  • store/class-b.js
// store/class-b.js
import { makeObservable, observable, action } from "mobx";
class classB {
  people = [
    { name: '张三' },
    { name: '李四' },
  ]

  constructor() {
    makeObservable(this, {
      people: observable,
      setPersonName: action.bound,
    });
  }

  setPersonName (index, name) {
    this.people[index].name = name;
  } 
}

export default new classB();
  • store/observable-a.js
// store/observable-a.js
import { observable } from "mobx";

const observableA = observable({
  todos: [
    {
      id: 1,
      name: "Todo 1",
      completed: false,
      assignee: null
    }
  ],
  addTodo(todo) 
  {
    _this.todos.push(todo);
  },
  subTodo (index)
  {
    _this.todos.splice(index, 1);
  },
  setTodoAssignee (todoIndex, assignee)
  {
    _this.todos[todoIndex].assignee = assignee;
  }
});

const _this = observableA;

export default observableA;
  • store/observable-b.js
// store/observable-b.js
import { observable } from "mobx";

const observableB = observable({
  people: [
    {
      name: "张三",
      age: 20,
    },
    {
      name: "李四",
      age: 20,
    },
    {
      name: "王五",
      age: 20,
    },
  ],
  setPersonName (index, name)
  {
    _this.people[index].name = name;
  }
})

const _this = observableB;

export default observableB;

测试用例:

  1. class + makeObservable() 创建的响应数据数据 A 和 B, 将B动态设置为A的属性值时,即A.x=B,B值更新时,A.x 会自动更新;
// components/class-observable-1.jsx
import StoreClassA from '../store/class-a';
import StoreClassB from '../store/class-b';
import { observer } from "mobx-react-lite";

const { todos, addTodo, subTodo, setTodoAssignee } = StoreClassA;

const TodoListComp = () => {
  
  const addNewTodo = () => {
    addTodo({
      id: Math.random(),
      name: 'todo' + (todos.length + 1),
      assignee: null
    })
  }

  return (
    <div>
      <ul>
        {
          todos.map((item, index) => {
            return (
              <li key={index}>
                <small>{item.id}</small> - 
                <span>{item.name}</span> - 
                { item.assignee ? <small>{item.assignee.name}</small> : null }
                <button onClick={subTodo.bind(this, index)}>-</button>
              </li>)
          })
        }
      </ul>
      <button onClick={addNewTodo}>add todo</button>
    </div>
  );
}

const PeopleToolComp = () => {
  const { people, setPersonName } = StoreClassB;
  return (
    <div>
      <ul>
        {
          people.map((item, index) => {
            return (
              <li key={index}>
                <span>{item.name}</span>
                -
                <small>{item.age}</small>
              </li>)
          })
        }
      </ul>
      <button onClick={ () => setTodoAssignee(0, people[0]) }>设置todos[0].assignee</button>
      <br />
      <input type="text" onChange={ e => setPersonName(0, e.target.value) }/>
    </div>
  )
}


const TodoListView = observer(TodoListComp);
const PeopleToolView = observer(PeopleToolComp);

export {
  TodoListView,
  PeopleToolView,
};

[x] 结论:当 people[0].name 发生变化时 todos[0].assignee.name 也会更新

  1. class + makeObservable() 创建的响应数据数据 A,observable() 创建的响应数据数据 B,将B动态设置为A的属性值时,即A.x=B,B值更新时,A.x会自动更新;
// components/class-observable-2.jsx
import StoreClassA from './../store/class-a';
import StoreObservableB from './../store/observable-b';
import { observer } from "mobx-react-lite";

const { todos, addTodo, subTodo, setTodoAssignee } = StoreClassA;

const TodoListComp = () => {
  
  const addNewTodo = () => {
    addTodo({
      id: Math.random(),
      name: 'todo' + (todos.length + 1),
      assignee: null
    })
  }

  return (
    <div>
      <ul>
        {
          todos.map((item, index) => {
            return (
              <li key={index}>
                <small>{item.id}</small> - 
                <span>{item.name}</span> - 
                { item.assignee ? <small>{item.assignee.name}</small> : null }
                <button onClick={subTodo.bind(this, index)}>-</button>
              </li>)
          })
        }
      </ul>
      <button onClick={addNewTodo}>add todo</button>
    </div>
  );
}

const PeopleToolComp = () => {
  const { people, setPersonName } = StoreObservableB;
  return (
    <div>
      <ul>
        {
          people.map((item, index) => {
            return (
              <li key={index}>
                <span>{item.name}</span>
                -
                <small>{item.age}</small>
              </li>)
          })
        }
      </ul>
      <button onClick={ () => setTodoAssignee(0, people[0]) }>设置todos[0].assignee</button>
      <br />
      <input type="text" onChange={ e => setPersonName(0, e.target.value) }/>
    </div>
  )
}


const TodoListView = observer(TodoListComp);
const PeopleToolView = observer(PeopleToolComp);

export {
  TodoListView,
  PeopleToolView,
};

[x] 结论:当 people[0].name 发生变化时 todos[0].assignee.name 也会更新

  1. observable() 创建的响应数据数据 A, class + makeObservable() 创建的响应式数据 B, 将B动态设置为A的属性值时,即A.x=B,B值更新时,A.x也会自动更新;
// components/class-observable-3.jsx
import StoreObservableA from '../store/observable-a';
import StoreClassB from '../store/class-b';
import { observer } from "mobx-react-lite";

const { todos, addTodo, subTodo, setTodoAssignee } = StoreObservableA;

const TodoListComp = () => {
  
  const addNewTodo = () => {
    addTodo({
      id: Math.random(),
      name: 'todo' + (todos.length + 1),
      assignee: null
    })
  }

  return (
    <div>
      <ul>
        {
          todos.map((item, index) => {
            return (
              <li key={index}>
                <small>{item.id}</small> - 
                <span>{item.name}</span> - 
                { item.assignee ? <small>{item.assignee.name}</small> : null }
                <button onClick={subTodo.bind(this, index)}>-</button>
              </li>)
          })
        }
      </ul>
      <button onClick={addNewTodo}>add todo</button>
    </div>
  );
}

const PeopleToolComp = () => {
  const { people, setPersonName } = StoreClassB;
  return (
    <div>
      <ul>
        {
          people.map((item, index) => {
            return (
              <li key={index}>
                <span>{item.name}</span>
                -
                <small>{item.age}</small>
              </li>)
          })
        }
      </ul>
      <button onClick={ () => setTodoAssignee(0, people[0]) }>设置todos[0].assignee</button>
      <br />
      <input type="text" onChange={ e => setPersonName(0, e.target.value) }/>
    </div>
  )
}


const TodoListView = observer(TodoListComp);
const PeopleToolView = observer(PeopleToolComp);

export {
  TodoListView,
  PeopleToolView,
};

[x] 结论:当 people[0].name 发生变化时 todos[0].assignee.name 也会更新

  1. observable() 创建的响应数据数据 A 和 B,将B动态设置为A的属性值时,即A.x=B,B值更新时,A.x会自动更新;
// components/class-observable-4.jsx
import StoreObservableA from '../store/observable-a';
import StoreObservableB from '../store/observable-b';
import { observer } from "mobx-react-lite";

const { todos, addTodo, subTodo, setTodoAssignee } = StoreObservableA;

const TodoListComp = () => {
  
  const addNewTodo = () => {
    addTodo({
      id: Math.random(),
      name: 'todo' + (todos.length + 1),
      assignee: null
    })
  }

  return (
    <div>
      <ul>
        {
          todos.map((item, index) => {
            return (
              <li key={index}>
                <small>{item.id}</small> - 
                <span>{item.name}</span> - 
                { item.assignee ? <small>{item.assignee.name}</small> : null }
                <button onClick={subTodo.bind(this, index)}>-</button>
              </li>)
          })
        }
      </ul>
      <button onClick={addNewTodo}>add todo</button>
    </div>
  );
}

const PeopleToolComp = () => {
  const { people, setPersonName } = StoreObservableB;
  return (
    <div>
      <ul>
        {
          people.map((item, index) => {
            return (
              <li key={index}>
                <span>{item.name}</span>
                -
                <small>{item.age}</small>
              </li>)
          })
        }
      </ul>
      <button onClick={ () => setTodoAssignee(0, people[0]) }>设置todos[0].assignee</button>
      <br />
      <input type="text" onChange={ e => setPersonName(0, e.target.value) }/>
    </div>
  )
}


const TodoListView = observer(TodoListComp);
const PeopleToolView = observer(PeopleToolComp);

export {
  TodoListView,
  PeopleToolView,
};

[x] 结论:当 people[0].name 发生变化时 todos[0].assignee.name 也会更新

总结:

当 observable() 和 class+makeObservable() 创建的响应式数据,两个响应式数据混用时,是可以继续保持响应性的;