这里是MobX概念的新手,但以为我遵守了规则。当我运行createProject("Foo")
时,出现此错误:
Error: [mobx] Computed values are not allowed to cause side effects by changing observables that are already being observed. Tried to modify: [email protected][..].children
我假设通过将原始节点分配给leafNodes
和rootNodes
,我只是制作新的本地变量,但它认为我正在更改原始的@observable
。构建上述数组时,我也曾尝试过Object.assign({}, node)
且没有任何更改。我应该如何构造这种结构以防止这种副作用?我有一个带有id和parentId的对象的平面数组,这些对象描述了标准的树层次结构。 tree
函数用实际对象替换id,并产生实际的嵌套结构。
import { decorate, observable, action, computed } from "mobx";
import remotedev from "mobx-remotedev";
import shortid from "shortid";
class ProjectsStore {
projects = [];
tasks = [];
createProject = (projectName, parentId = null) => {
const project = {
type: "project",
id: shortid.generate(),
name: projectName,
parentId: parentId,
children: []
};
this.projects.push(project);
return project;
};
createTask = (taskName, parentId = null) => {
const task = {
type: "task",
id: shortid.generate(),
name: taskName,
parentId: parentId
};
this.tasks.push(task);
return task;
};
get tree() {
// Separate root nodes and all others (leaf nodes)
let leafNodes = [];
let rootNodes = this.projects.filter(node => {
if (!node.parentId) {
return node;
} else {
leafNodes.push(node);
return false;
}
});
// Merge the tasks and non-root projects
leafNodes = leafNodes.concat(this.tasks);
// If the current node is a project, RECURSIVELY add the child nodes to
// it into the .children array
const populate = node => {
if (node.type === "project") {
// Search all non-root nodes to see if their parentId matches the
// current node's id. This designates it as a child of the current node.
// THIS IS WHERE THE ERROR HAPPENS!
node.children = leafNodes.filter(leaf => node.id === leaf.parentId);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^
for (let i = 0; i < node.children.length; i++) {
node.children[i] = populate(node.children[i]);
}
}
return node;
};
// Iterate over all root nodes and return their populated trees.
return rootNodes.map((node, n) => {
return populate(node);
});
}
}
decorate(ProjectsStore, {
projects: observable,
tasks: observable,
createProject: action,
createTask: action,
tree: computed
});
export default remotedev(ProjectsStore);
解决了我自己的问题(种类)。因此,我已经学会了有关Mobx和代理的TON来尝试解决此问题,似乎最好的解决方案是架构更改。我以为可以将节点存储在平面数组中,然后使用递归函数动态构建层次结构。事实证明,我无法更改compute
函数的结构(上面的错误^^),并且我无法复制节点,因为那样会破坏observe
-能力。
因此,解决方案是使它们保持平坦并更改我的React组件渲染以递归渲染层次结构。 结果使数据和逻辑与表示分离。双赢!