TreeView 维护focused node id within its state。当您使用不同的结构重新渲染树时(例如删除“根”节点),TreeItems 将被重新安装,而不仅仅是重新渲染。 TreeItem 基于 TreeView 上下文监控 whether or not it should be focused,如果发生变化,它会抓住焦点。当TreeItem 挂载时,该焦点逻辑将执行。通常TreeItem 不会将焦点放在挂载上,但在您的特定场景中,因为TreeView 保持一致并记住最后一个焦点TreeItem,但是所有项目都被重新挂载,它会将焦点带回那个TreeItem。
问题的另一个方面是TreeViewremembers its nodes。它@ 987654324@,但看起来您的场景可能会暴露该逻辑中的错误并且键入(一旦焦点回到树项上)试图查找不再存在的节点的父节点(尽管我会需要使用更简单的代码示例进一步深入研究,以确定为什么 nodeMap 不太正确以及这是否真的是一个错误)。
您可以通过在搜索后设置新树时更改TreeView 的键来修复焦点转移和过时的nodeMap 信息。这会导致重新挂载 TreeView,因此它不再记住最后一个焦点节点或旧节点映射。
这是您沙盒中代码的修改版本(我的更改以“由 Ryan 添加”表示):
import React, { useState } from "react";
import TreeViewFilter from "./TreeViewFilter";
import TreeView from "@material-ui/lab/TreeView";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import { Folder } from "@material-ui/icons";
import TreeItem from "@material-ui/lab/TreeItem";
import { makeStyles } from "@material-ui/core/styles";
import { amber } from "@material-ui/core/colors";
import _ from "lodash";
const useStyles = makeStyles({
root: {
height: 216,
flexGrow: 1,
maxWidth: 400
}
});
enum NodeType {
FOLDER = 0,
SCHEMA
}
type TreeNode = {
name: string;
type: NodeType;
parent: string | null;
childNodes: Array<TreeNode>;
};
export interface ITreeViewProps {
tree: TreeNode;
fetchItem?: () => void;
}
export default function TreeViewContainer(props: ITreeViewProps) {
const classes = useStyles();
const [searchValue, setSearchValue] = useState("");
const [tree, setTree] = useState(props.tree);
// ** Added by Ryan ** New treeKey state
const [treeKey, setTreeKey] = useState(1);
function fetchItem(id: string) {
// inicjacja pobierania schematu/listy alarmów/ raport/ wykresu
console.log("Fetch " + id);
}
function renderTree(tree: any) {
if (Array.isArray(tree)) {
return tree.map(item => buildTree(item));
} else {
return buildTree(tree);
}
}
function buildTree(tree: TreeNode) {
return (function recursive(currentNode: TreeNode) {
if (currentNode.type === NodeType.FOLDER) {
return (
<TreeItem
key={currentNode.name}
nodeId={`${currentNode.type}${currentNode.name}`}
label={
<div>
<Folder style={{ color: amber[500] }} />{" "}
<span>{currentNode.name}</span>
</div>
}
>
{currentNode.childNodes.map(node => recursive(node))}
</TreeItem>
);
}
if (currentNode.type === NodeType.SCHEMA) {
return (
<TreeItem
key={currentNode.name}
nodeId={`${currentNode.type}${currentNode.name}`}
onClick={() => {
fetchItem(currentNode.name);
}}
label={currentNode.name + ".sh"}
/>
);
}
return null;
})(tree);
}
const searchTree = (tree: TreeNode, searchValue: string, callback: any) => {
const searchRE = new RegExp(searchValue, "i");
return (function recurse(currentNode: TreeNode) {
for (let i = 0, length = currentNode.childNodes.length; i < length; i++) {
recurse(currentNode.childNodes[i]);
}
if (currentNode.name.match(searchRE))
callback({
...currentNode,
childNodes: currentNode.childNodes.filter(node =>
node.name.match(searchRE)
)
});
})(tree);
};
const doSearch = (text: string) => {
console.log("-------------------->>>>");
setSearchValue(text);
let newTree: any = [];
searchTree(props.tree, text, function(node: any) {
console.log(node);
newTree.push(node);
});
console.log("===============");
console.log(newTree); // usunąć item, którego parent jest tablicy
function hasParentInCollection(item: TreeNode, index, arr) {
if (arr.find((el: any) => el.name === item.parent)) return false;
else return true;
}
newTree = newTree.filter(hasParentInCollection);
//set new tree
console.log("++++++++++++++++++++++++");
console.log(newTree);
setTree(newTree);
// ** Added by Ryan ** Update treeKey state
setTreeKey(oldKey => oldKey + 1);
};
const treeItems = renderTree(tree);
return (
<div>
<div>
<TreeViewFilter doSearch={doSearch} value={searchValue} />
</div>
<div>
{/* ** key={treeKey} added by Ryan */}
<TreeView
key={treeKey}
className={classes.root}
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
{treeItems}
</TreeView>
</div>
</div>
);
}