Javascript 动态添加到嵌套数组
我试图在react中构建一个treeview组件,其中基于用户扩展的节点获取树的数据 想法 当第一个节点被扩展时,一个HTTP请求被发送到一个服务,该服务返回该节点的所有子节点。当另一个节点被扩展时,该节点的子节点被获取,等等。我有一个非常大的数据集,所以我更喜欢这种获取方法,而不是在网站启动时获取所有数据 问题 这可能是扩展部门节点时服务返回的数据示例Javascript 动态添加到嵌套数组,javascript,reactjs,Javascript,Reactjs,我试图在react中构建一个treeview组件,其中基于用户扩展的节点获取树的数据 想法 当第一个节点被扩展时,一个HTTP请求被发送到一个服务,该服务返回该节点的所有子节点。当另一个节点被扩展时,该节点的子节点被获取,等等。我有一个非常大的数据集,所以我更喜欢这种获取方法,而不是在网站启动时获取所有数据 问题 这可能是扩展部门节点时服务返回的数据示例 { "division": { "id": "1234", "name": "string", "address": "string"
{
"division": {
"id": "1234",
"name": "string",
"address": "string",
},
"children": [
{
"id": "3321",
"parentId": "1234",
"name": "Marketing",
"address": "homestreet",
},
{
"id": "3323",
"parentId": "1234",
"name": "Development",
"address": "homestreet",
}
]
}
然后我可以扩展开发节点并获取该节点的子节点
我想我需要某种嵌套数组,但我不确定如何处理保持数组的正确顺序,以便获得正确的树层次结构。因为用户可以选择展开任何节点。有人能帮忙吗 我对React不是特别熟悉,但一般来说,每个节点都必须有一个
子元素元素,这将是一个空数组。我假设当用户展开一个节点时,您知道他们正在展开哪个节点(当用户单击展开按钮时,节点对象可能对您可用),因此获取子节点并用服务器的数据替换空的子节点数组是很简单的。我想我的原始答案是(以下,因为它已经被接受)是一个反模式或没有思考问题的例子
React组件树本身就是一棵树。因此,我认为如果你有一个TreeNode
组件或类似的组件,知道如何加载它的子组件,这是很好的,比如:
function TreeNode({id, name, parentId, address}) {
// The nodes, or `null` if we don't have them yet
const [childNodes, setChildNodes] = useState(null);
// Flag for whether this node is expanded
const [expanded, setExpanded] = useState(false);
// Flag for whether we're fetching child nodes
const [fetching, setFetching] = useState(false);
// Flag for whether child node fetch failed
const [failed, setFailed] = useState(false);
// Toggle our display of child nodes
const toggleExpanded = useCallback(
() => {
setExpanded(!expanded);
if (!expanded && !childNodes && !fetching) {
setFailed(false);
setFetching(true);
fetchChildNodes(id)
.then(nodes => setChildNodes(nodes.map(node => <TreeNode {...node} />)))
.catch(error => setFailed(true))
.finally(() => setFetching(false));
}
},
[expanded, childNodes, fetching]
);
return (
<div class="treenode">
<input type="button" onClick={toggleExpanded} value={expanded ? "-" : "+"} style={{width: "28px"}}/>
<span style={{width: "4px", display: "inline-block"}}></span>{name}
{failed && expanded && <div className="failed">Error fetching child nodes</div>}
{fetching && <div className="loading">Loading...</div>}
{!failed && !fetching && expanded && childNodes && (childNodes.length > 0 ? childNodes : <div class="none">(none)</div>)}
</div>
);
}
这包括任何“ajax”操作失败的概率为十分之一,因此可以进行测试。只需折叠并再次展开即可重试
我会让树的每个节点成为一个单独的组件,称为“TreeNode”或其他什么,那么它必须包含的是:
- 其父节点的ID(如果是根节点,则可以为空)
- 它的子ID列表
- 显示是否展开的布尔属性
- 最后,它自己的负载数据(在您的例子中是名称和地址)
在这方面,“树”组件应仅包含单个属性:
- 其根节点的ID
然后,当用户单击某个TreeNode时,它将触发一个事件,TreeNode将处理该事件:
- 若它还并没有展开,那个么它将开始展开,这将导致获取请求
- 如果它已经被“扩展”——那么它取决于您的需求——它可以被折叠,也可以不折叠——无论它是否适合您的用例
此设置意味着您只需要两种类型的组件,并且不需要任何嵌套阵列
每个TreeNode组件负责如何呈现其自己的有效负载数据,然后呈现其所有子组件,因此它必须知道如何应用视觉样式等。但这与任何可见组件都是一样的
因此,关键是每个节点只负责一个更深层次,即它的直接子节点,而对孙子辈的情况保持不可知论,等等
更新:
一个小警告:每个TreeNode都必须阻止鼠标点击向上冒泡。这里有一个专门的问题,所以:
更新2
另外,有两种方法可以保存每个节点的回迁数据:
在父组件内保存所有子数据,包括有效负载(不仅仅是ID)。在这种情况下,上面的“子ID列表”将转到“子数据列表:ID和有效负载”
所有获取的数据都被“全局”保存,例如在树组件内部。然后,在呈现子节点时,每个树节点都必须引用该知识源并通过ID检索数据
这种情况下的树组件可以使用JS映射对象(ID->NodeData)
在第二种设置中,如果不使用树组件,每个树节点也应该保留对树或直接映射的引用。类似的情况。我的第一个想法是,每个节点都有自己的状态。你是需要应用程序中的数据,还是可以单独驻留在节点中?我不确定我是否理解你的问题。你能重新措辞吗?谢谢你的回答。你所说的id路径是什么意思?@John-我一直想在某处定义它。:-)我指的是一个数组,每个节点的id指向目标节点。对于开发
,这将是[“1234”,“3323”]
。但是你不必这样做,你可以稍后通过id
找到路径,它只需要搜索。再次感谢:)因为我是新手,请确保你引用的树节点是组件的名称?@John-一个你在代码中定义的组件,是的。还有一些我应该提到的事情。:-)@约翰-事实上,我想知道这个答案是否是反模式的。DOM/React组件树已经是一个树。看起来TreeNode
应该直接处理其子节点的更新,而TreeView
组件本质上应该只是根节点的容器。