React 中的递归组件(二)--示例
React 组件构建嵌套文件浏览器
首先,在 src
文件夹中创建一个新的 React 应用程序和一个 data
文件夹。然后,在 data
中创建 data.js
,并将 “为什么、何时在 React 中使用递归组件” 部分的数据复制并粘贴到后面的部分。
现在,将 App.js
文件的代码替换为以下代码:
import React from "react";
import { data } from "./data/data";
const NonRecursiveComponent = ({ data }) => {
return <div>Non Recursive Component</div>;
};
const App = () => {
return (
<div style={{ margin: "8px" }}>
<NonRecursiveComponent data={data} />
</div>
);
};
export default App;
我们在上面的代码中创建了一个 NonRecursiveComponent
,并在 App
组件中渲染它。然后,我们将 data
属性从 App
传递给 NonRecursiveComponent
。
在 NonRecursiveComponent
中,将现有代码替换为以下内容:
const NonRecursiveComponent = ({ data }) => {
return (
<div>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
</div>
);
})}
</div>
);
};
上面的代码将呈现所有 parent
(第一级)数据并将其显示在页面上:
现在,让我们使用第二个 return
语句中的 map
方法来渲染 children
。代码所示:
const NonRecursiveComponent = ({ data }) => {
return (
<div>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
{parent.children.map((child) => {
return (
<div key={child.name} style={{ paddingLeft: "20px" }}>
<span>{child.name}</span>
</div>
);
})}
</div>
);
})}
</div>
);
};
您会在页面上看到 parent
的所有 children
:
渲染 grandchildren
。
const NonRecursiveComponent = ({ data }) => {
return (
<div>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
{parent.children.map((child) => {
return (
<div key={child.name} style={{ paddingLeft: "20px" }}>
<span>{child.name}</span>
{child.children &&
child.children.map((grandChild) => {
return (
<div key={grandChild.name} style={{ paddingLeft: "20px" }}>
<span>{grandChild.name}</span>
</div>
);
})}
</div>
);
})}
</div>
);
})}
</div>
);
};
您应该在页面上看到:
最后,我们需要呈现 great-grandchildren
。我们需要做与渲染 children
和 grandchildren
相同的事情:
const NonRecursiveComponent = ({ data }) => {
return (
<div>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
{parent.children.map((child) => {
return (
<div key={child.name} style={{ paddingLeft: "20px" }}>
<span>{child.name}</span>
{child.children &&
child.children.map((grandChild) => {
return (
<div
key={grandChild.name}
style={{ paddingLeft: "20px" }}
>
<span>{grandChild.name}</span>
{grandChild.children &&
grandChild.children.map((greatGrandChild) => {
return (
<div
key={greatGrandChild.name}
style={{ paddingLeft: "20px" }}
>
<span>{greatGrandChild.name}</span>
</div>
);
})}
</div>
);
})}
</div>
);
})}
</div>
);
})}
</div>
);
};
到止,我们已经使用 React 组件构建了一个基本的嵌套文件浏览器组件。但是,如您所见, NonRecursiveComponent
代码似乎在为每个嵌套数据级别重复自身。随着我们数据的嵌套级别的增加,这段代码会变得更长,使其更难理解和维护。
那么,我们如何解决这个问题呢?
在 React 中使用递归组件构建嵌套文件浏览器
让我们从在 App.js
文件中创建一个新的 RecursiveComponent
开始。然后,将 App
中呈现的 NonRecursiveComponent
替换为 RecursiveComponent
。
const RecursiveComponent = ({ data }) => {
return (
<div style={{ paddingLeft: "20px" }}>
Recursive Component
</div>
);
};
const App = () => {
return (
<div style={{ margin: "8px" }}>
<RecursiveComponent data={data} />
</div>
);
};
渲染所有 parent
数据:
const RecursiveComponent = ({ data }) => {
return (
<div style={{ paddingLeft: "20px" }}>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
</div>
);
})}
</div>
);
};
接下来,让我们使用递归来渲染所有嵌套的文件和文件夹数据。
首先,使用不同的 data
道具从内部渲染 RecursiveComponent
。
其次,我们需要一个基本条件来停止渲染 RecursiveComponent
。
在我们的例子中,当 children
的长度为零或它们不存在时,此时我们不会调用 RecursiveComponent
。
const RecursiveComponent = ({ data }) => {
return (
<div style={{ paddingLeft: "20px" }}>
{data.map((parent) => {
return (
<div key={parent.name}>
<span>{parent.name}</span>
<div>
{parent.children && <RecursiveComponent data={parent.children} />}
</div>
</div>
);
})}
</div>
);
};
通过几行代码,我们实现了相同的输出。这就是 React 中递归的魔力。
现在,让我们对嵌套的文件和文件夹实施 show/hide
。
首先,我们需要使用数据中的 isFolder
作为条件, button
作为文件夹名称, span
作为文件名称。我们这样做是因为我们只会将 onClick
事件添加到文件夹而不是文件以显示或隐藏特定文件夹内的所有文件和文件夹。
const RecursiveComponent = ({ data }) => {
return (
<div style={{ paddingLeft: "20px" }}>
{data.map((parent) => {
return (
<div key={parent.name}>
{parent.isFolder && <button>{parent.name}</button>}
{!parent.isFolder && <span>{parent.name}</span>}
<div>
{parent.children && <RecursiveComponent data={parent.children} />}
</div>
</div>
);
})}
</div>
);
};
现在,让我们通过在 RecursiveComponent
中使用 show/hide
Hook 创建一个状态来实现 show/hide
,如下所示:
import { useState } from "react";
const RecursiveComponent = ({ data }) => {
const [showNested, setShowNested] = useState({});
// ...
// ...
};
showNested
状态变量将存储所有打开的文件夹,如下所示:
{
public: true, // 文件夹打开,设置为 true
src: false // 文件夹关闭 ,设置为 false
}
现在,创建一个函数来处理 show/hide
:
const RecursiveComponent = ({ data }) => {
const [showNested, setShowNested] = useState({});
const toggleNested = (name) => {
setShowNested({ ...showNested, [name]: !showNested[name] });
};
// ...
// ...
};
toggleNested
函数接受文件夹名称作为参数,然后使用 setShowNested
函数更新 showNested
中该文件夹的值。这会将它从 false
更改为 true
,反之亦然。
现在,让我们向 button
添加一个 onClick
事件以调用 toggleNested
。然后,当用户单击任何文件夹时,将文件夹的名称作为参数传递,如下所示:
const RecursiveComponent = ({ data }) => {
// ...
return (
<div style={{ paddingLeft: "20px" }}>
{data.map((parent) => {
return (
<div key={parent.name}>
{parent.isFolder && (
<button onClick={() => toggleNested(parent.name)}>
{parent.name}
</button>
)}
// ...
// ...
</div>
);
})}
</div>
);
};
最后一步是更新 display
CSS 属性,我们将添加到 div
包装 RecursiveComponent
内的 RecursiveComponent
。当用户选择文件夹时,我们将通过将文件夹名称作为 key
添加到该对象来更新 showNested
对象。我们还将其值设置为 true
并添加检查以查看文件夹名称是否存在于 showNested
中。
然后,我们将 display
设置为 block
。否则,我们将其设置为 none
以隐藏嵌套的文件和文件夹:
const RecursiveComponent = ({ data }) => {
// ...
return (
<div style={{ paddingLeft: "20px" }}>
{data.map((parent) => {
return (
<div key={parent.name}>
// ...
// ...
<div style={{ display: !showNested[parent.name] && "none" }}>
{parent.children && <RecursiveComponent data={parent.children} />}
</div>
</div>
);
})}
</div>
);
};
这样,就完成了!
结论
在本文中,您了解了 React 中的递归组件、如何构建它们以及我们为什么要使用它们。此外,我还通过一个真实示例展示了递归与循环的不同之处。希望您学到了对您的下一个 React 项目有用的新知识。
谢谢!
转载自:https://juejin.cn/post/7206701761682505786