简体   繁体   English

需要帮助在 React 中使用给定的 json 结构创建文件夹树组件

[英]Need help creating a folder tree component in React with the given json structure

I am trying to build a folder tree component where initially the component will only render the names of items at the first layer (item1, item2, item3), then when an specific item is clicked, it would show me everything listed on the next layer for that item(ie click on item1 would show item1.1 and item1.2, click on item1.1 will show item1.1.1 ).我正在尝试构建一个文件夹树组件,最初该组件只会呈现第一层的项目名称(item1、item2、item3),然后当单击特定项目时,它会显示下一层列出的所有内容对于该项目(即单击item1将显示item1.1item1.2,单击item1.1将显示item1.1.1 )。 This should be done in a loop until it reaches the final layer with the just the attributes (attr1, attr2, attr3).这应该在一个循环中完成,直到它到达只有属性(attr1、attr2、attr3)的最后一层。

Note: I have simplified the item names for demo purposes, but in reality they don't follow a specific pattern/naming system.注意:出于演示目的,我已经简化了项目名称,但实际上它们并不遵循特定的模式/命名系统。

import React, {useState, useEffect} from 'react';


const Testing = () => {
    const [expand, setExpand] = useState(false);
    
    const data = {
        "item1": {
            "item1.1": {
                "item1.1.1": {
                    "item1.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            },
            "item1.2": {
                "item1.2.1": {
                    "item1.2.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            }
        },
        "item2": {
            "item2.1": {
                "item2.1.1": {
                    "item2.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                },
                "item2.1.2": {
                    "item2.1.2.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    },
                    "item2.1.2.2": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            }
        },
        "item3": {
            "item3.1": {
                "item3.1.1": {
                    "item3.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                },
                "item3.1.2": {
                    "attr1": [],
                    "attr2": "",
                    "attr3": []
                }
            }
        }

    }

    function parse(data) {
        if (typeof data === 'object') {
            return (
                <li>
                    <ul>
                        {Object.entries(data).map(([key, value]) => (
                            <>
                                <li>
                                    {key}: {typeof value === 'string' ? value : ''}
                                </li>
                                {parse(value)}
                            </>
                        ))}
                    </ul>
                </li>
            );
        }
        if (typeof data === 'object') return (<li>{data}</li>);
        return null;
    }
    
    return (
        <div>
            <div className="App">
                {Object.entries(data).map(([key, value]) => {
                    return (
                        <ul>
                            <span onClick={() => setExpand(!expand)}>{key}</span>
                            <br />
                            <div style={{ display: expand ? "block" : "none", paddingLeft: 15 }}>
                                {parse(value)}
                            </div>
                        </ul>
                    );
                })}
            </div>
        </div>
    )
}

export default Testing;

Here a picture of the output I'm getting right now with the code above: current output ;这是我现在用上面的代码得到的输出图片: current output ; it shows item1, item2, item3 in a list;它在列表中显示 item1、item2、item3; but when I click on any of them, it will just render everything else, I'm trying to find a way so that it behaves similar to a file directory tree as shown in the demo here: https://codesandbox.io/s/folder-structuring-t6oj4但是当我点击它们中的任何一个时,它只会呈现其他所有内容,我正在尝试找到一种方法,使其行为类似于文件目录树,如下面的演示所示: https ://codesandbox.io/s /文件夹结构-t6oj4

The issue is that in the demo they use a recursive component that has its own expand state managed with a hook.问题在于,在演示中,他们使用了一个递归组件,该组件具有自己的expand状态,并通过钩子进行管理。 So every Folder will have a distinct value for the expand variable that is inside their scope.因此,每个Folder都将具有其范围内的expand变量的不同值。

On the other hand, your Testing component manages a single expand state and the whole rendering uses that state for every "folder" that's the reason why when you click a folder it toggles the state for the whole component, what you should do is refactor your component so that it also manages its own state in each Folder, something like this which is in the demo:另一方面,您的Testing组件管理单个expand状态,并且整个渲染为每个“文件夹”使用该状态,这就是为什么当您单击文件夹时它会切换整个组件的状态,您应该做的是重构您的组件,以便它还在每个文件夹中管理自己的状态,就像在演示中一样:

import React, { useState } from "react";

function Folder ({ name, file }) {
  const [expand, setExpand] = useState(false);
  if (typeof file !== "object") return <span>{file}</span>;
  return (
    <div>
      <span onClick={() => setExpand(!expand)}>{name}</span>
      <br/>
      <div style={{ display: expand ? "block" : "none", paddingLeft: 15 }} >
        {
          Object.entries(file).map(([key, value]) => (
            <Folder key={key} name={key} file={value} />
          ))
        }
      </div>
    </div>
  );
}

And then just call it in your component:然后在你的组件中调用它:

import React from 'react';


const Testing = () => {
    const data = {
        "item1": {
            "item1.1": {
                "item1.1.1": {
                    "item1.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            },
            "item1.2": {
                "item1.2.1": {
                    "item1.2.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            }
        },
        "item2": {
            "item2.1": {
                "item2.1.1": {
                    "item2.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                },
                "item2.1.2": {
                    "item2.1.2.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    },
                    "item2.1.2.2": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                }
            }
        },
        "item3": {
            "item3.1": {
                "item3.1.1": {
                    "item3.1.1.1": {
                        "attr1": [],
                        "attr2": "",
                        "attr3": []
                    }
                },
                "item3.1.2": {
                    "attr1": [],
                    "attr2": "",
                    "attr3": []
                }
            }
        }

    }
    
    return (
        <div>
            <div className="App">
                <Folder name="/root" file={data} />
            </div>
        </div>
    )
}

Edit: Refactored the code so that only the selected folder expands on click编辑:重构代码,以便只有选定的文件夹在单击时展开

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM