likes
comments
collection
share

React 中的递归组件(二)--示例

作者站长头像
站长
· 阅读数 75

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 (第一级)数据并将其显示在页面上:

React 中的递归组件(二)--示例

现在,让我们使用第二个 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 :

React 中的递归组件(二)--示例

渲染 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>
  );
};

您应该在页面上看到:

React 中的递归组件(二)--示例

最后,我们需要呈现 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 中的递归组件(二)--示例

到止,我们已经使用 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 中的递归组件(二)--示例

React 中的递归组件(二)--示例 通过几行代码,我们实现了相同的输出。这就是 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
评论
请登录