#reactjs #recursion
#reactjs #рекурсия
Вопрос:
Я пытаюсь создать динамический просмотр дерева с помощью Reactjs и material UI, но когда у меня есть уровни рекурсии, я получил ошибку Uncaught RangeError: Maximum call stack size exceeded
в коде TreeItem
вам необходимо рассмотреть понимание этой части {item.sub amp;amp; TreeItems(item.sub)}
когда у элемента есть sub, это возвращает a <TreeItem
в противном случае он ничего не делает
также обратите внимание, что я создал это представление дерева без рекурсии, и оно работало очень весело, вот так
<TreeView
disableSelection
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
<TreeItem nodeId="1" label="1">
<TreeItem nodeId="12" label="12">
<TreeItem nodeId="3" label="3">
<TreeItem nodeId="13" label="13"></TreeItem>
</TreeItem>
</TreeItem>
</TreeItem>
</TreeView>
моя структура набора данных
const myData = [
{ id: 1, text: "value" },
{
id: 2,
text: "xxx",
sub: [
{
id: 10,
text: "value",
sub: [
{
id: 100,
text: "value",
sub: [{ id: 20, text: "value", sub: [{ id: 200, text: "value" }] }],
},
],
},
],
},
];
моя рекурсивная функция
function TreeItems(myData) {
return myData.map((item, index) => (
<TreeItem
onLabelClick={(e) => e.preventDefault()}
key={index}
nodeId={`${index}`}
label={
<div
style={{ display: "flex" }}
draggable={isDraggable}
{...Draggable(item, index, Update, setDraggable)}
>
<DragIndicatorIcon
onMouseDown={(e) => setDraggable(true)}
onMouseUp={(e) => setDraggable(false)}
/>
<Text>{item.text}</Text>
</div>
}
>
{item.sub amp;amp; TreeItems(item.sub)}
</TreeItem>
));
}
—
примечание: вероятно, нет необходимости видеть мой полный, но на всякий случай.
мой полный код
app.tsx
import React from "react";
import "./App.css";
import Tree from "./Components/Tree";
// import { DataGrid } from "@material-ui/data-grid";
import RouterBreadcrumbs from "./Components/Nav";
import { BrowserRouter, Route } from "react-router-dom";
import SimpleBreadcrumbs from "./Components/BreadCrumbs";
const My = [
{
id: 0,
text: (
<div>
this is an example <b>data</b>
</div>
),
},
{ id: 1, text: "test tow" },
{ id: 2, text: "test three" },
{
id: 3,
text: "main",
sub: [
{ id: 4, text: "sub 1" },
{ id: 5, text: "sub 2" },
],
},
];
const Home = [
{ id: 1, text: "value" },
{
id: 2,
text: "xxx",
sub: [
{
id: 10,
text: "value",
sub: [
{
id: 100,
text: "value",
sub: [{ id: 20, text: "value", sub: [{ id: 200, text: "value" }] }],
},
],
},
],
},
];
function App() {
return (
<BrowserRouter>
<div className="App">
<SimpleBreadcrumbs />
<RouterBreadcrumbs />
<Route exact path="/Home" component={(e: any) => Tree(Home)} />
<Route exact path="/My" component={(e: any) => Tree(My)} />
</div>
</BrowserRouter>
);
}
export default App;
export function my(x: string) {
return x.toUpperCase();
}
tree.tsx
import React, { useReducer, useState } from "react";
import TreeView from "@material-ui/lab/TreeView";
import ExpandMoreIcon from "@material-ui/icons/ExpandMore";
import ChevronRightIcon from "@material-ui/icons/ChevronRight";
import TreeItem from "@material-ui/lab/TreeItem";
import Draggable from "../Functions/Draggable";
import DragIndicatorIcon from "@material-ui/icons/DragIndicator";
import Text from "./Text";
function deleting(state, action) {
state.forEach((item) => {
if (item.id === action.i.item.id) {
state.splice(action.i.index, 1);
} else if (item.id !== action.i.item.id amp;amp; item.sub) {
deleting(item.sub, action);
}
});
return state;
}
function adding(state, action) {
state.forEach((item) => {
if (item.id === action.item.id) {
state.splice(action.f, 0, action.i.item);
} else if (item.sub) {
adding(item.sub, action);
}
});
return state;
}
function reordering(state, action) {
const newState = deleting(state, action);
const newState2 = adding(newState, action);
return newState2;
}
function subbing(state, action) {
state.forEach((item) => {
if (item.id === action.item.id) {
if (item.sub) {
Object.assign(item.sub, [...item.sub, action.i.item]);
}
if (!item.sub) {
Object.assign(item, { sub: [action.i.item] });
console.log(state);
}
} else if (item.sub) {
console.log("infient");
subbing(item.sub, action);
}
});
return state;
}
function Tree(myData) {
const [isDraggable, setDraggable] = useState(false);
const [state, setData] = useState(myData);
console.log(state);
function Update(item, i, f, p) {
const action = { item: item, i: i, f: f, p: p };
setData((pre) => {
if (p === "on") {
const newPre = deleting(pre, action);
const newPre2 = subbing(newPre, action);
return newPre2;
} else {
const newPre = deleting(pre, action);
const newPre2 = reordering(newPre, action);
return newPre2;
}
});
}
function TreeItems(state) {
return state.map((item, index) => (
<TreeItem
onLabelClick={(e) => e.preventDefault()}
key={index}
nodeId={`${index}`}
label={
<div
style={{ display: "flex" }}
draggable={isDraggable}
{...Draggable(item, index, Update, setDraggable)}
>
<DragIndicatorIcon
onMouseDown={(e) => setDraggable(true)}
onMouseUp={(e) => setDraggable(false)}
/>
<Text>{item.text}</Text>
</div>
}
>
{item.sub amp;amp; TreeItems(item.sub)}
</TreeItem>
));
}
return (
<div>
<TreeView
disableSelection
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
{TreeItems(state)}
</TreeView>
</div>
);
}
export default Tree;