我正在尝试创建一个递归组件,将其状态存储在mobx可观察对象中。
由于某种特殊的原因,如果可观察对象在其属性中链接另一个可观察对象,则当可观察状态发生变化时,来自mobx-react lite的observer
hoc不会触发重新渲染。
这里是一个例子,当可观察状态发生变化时,深度超过1的元素不会被重新渲染。
...
const NodeView = (props: { node: Node }) => {
useEffect(() => {
autorun(() => {
console.log(`(autorun) ${props.node.label} is expanded: ${props.node.expanded}`);
// WRONG: when the node is a child of another node, this runs, but the NodeView is not re-rendered
});
}, []);
console.log(`rerendering ${props.node.label} `);
return (
<>
<div
className="nodeHeader"
onClick={action(() => {
props.node.expanded = !props.node.expanded;
})}
>
{props.node.label}
</div>
{props.node.expanded && (
<div className="row">
<div className="offset" />
<div className="column">
{props.node.children.map((child, index) => (
<NodeView key={index} node={child} />
))}
</div>
</div>
)}
</>
);
};
export default memo(observer(NodeView));
以下是可观察对象的创建方式:
...
interface Node {
label: string;
expanded: boolean;
children: Node[];
nonObservedStuff: any;
}
const turnIntoObservable = (node: Node) => {
const children = node.children.map((child) => turnIntoObservable(child));
let observableNode: Node = { ...node, children };
// i'm trying to make observable not all, but only some specific properties
observableNode = makeObservable(observableNode, {
expanded: true,
children: observable.shallow
});
return observableNode;
};
let rootNodes: Node[] = ...
rootNodes = rootNodes.map((node) => turnIntoObservable(node));
这里是codesandbox演示
为什么改变一个可观察对象的状态,并通过其属性中的另一个可观测对象进行链接,不会导致重新呈现观察到该可观测对象的组件?
您将observer
组件导出为默认组件(export default memo(observer(NodeView));
(,但在NodeView
本身内部,您使用的是非观察器NodeView
您需要立即用observer包装它,所以递归版本也将是被动的:
const NodeView = observer((props: { node: Node }) => {}
此外,memo
会自动应用于所有observer
组件,无需手动重新应用。