반응형
참고
- Mui Tree View로 파일, 폴더 뷰 만들기
- Mui Tree View로 파일, 폴더 뷰 만들기 (with Node JS)
mui tree view의 Controlled tree view를 적용시켜보자.
위의 예제 코드는 다음과 같다.
import * as React from 'react';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import TreeView from '@mui/lab/TreeView';
import TreeItem from '@mui/lab/TreeItem';
export default function ControlledTreeView() {
const [expanded, setExpanded] = React.useState([]);
const [selected, setSelected] = React.useState([]);
const handleToggle = (event, nodeIds) => {
setExpanded(nodeIds);
};
const handleSelect = (event, nodeIds) => {
setSelected(nodeIds);
};
const handleExpandClick = () => {
setExpanded((oldExpanded) =>
oldExpanded.length === 0 ? ['1', '5', '6', '7'] : [],
);
};
const handleSelectClick = () => {
setSelected((oldSelected) =>
oldSelected.length === 0 ? ['1', '2', '3', '4', '5', '6', '7', '8', '9'] : [],
);
};
return (
<Box sx={{ height: 270, flexGrow: 1, maxWidth: 400, overflowY: 'auto' }}>
<Box sx={{ mb: 1 }}>
<Button onClick={handleExpandClick}>
{expanded.length === 0 ? 'Expand all' : 'Collapse all'}
</Button>
<Button onClick={handleSelectClick}>
{selected.length === 0 ? 'Select all' : 'Unselect all'}
</Button>
</Box>
<TreeView
aria-label="controlled"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
expanded={expanded}
selected={selected}
onNodeToggle={handleToggle}
onNodeSelect={handleSelect}
multiSelect
>
<TreeItem nodeId="1" label="Applications">
<TreeItem nodeId="2" label="Calendar" />
<TreeItem nodeId="3" label="Chrome" />
<TreeItem nodeId="4" label="Webstorm" />
</TreeItem>
<TreeItem nodeId="5" label="Documents">
<TreeItem nodeId="6" label="MUI">
<TreeItem nodeId="7" label="src">
<TreeItem nodeId="8" label="index.js" />
<TreeItem nodeId="9" label="tree-view.js" />
</TreeItem>
</TreeItem>
</TreeItem>
</TreeView>
</Box>
);
}
Mui Tree View로 파일, 폴더 뷰 만들기 (with Node JS)에서 localData에 경로가 있는 경우에 적용하였다.
import React, { useEffect, useState } from "react";
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import TreeItem from "@mui/lab/TreeItem";
let localData = {
child: [
{
label: "D:",
nodeId: 0,
child: [
{
label: "github",
nodeId: 1,
child: [
{
label: "globfiles",
nodeId: 2,
child: [
{
label: "abc1",
nodeId: 3,
child: [
{ label: "abc1_jsonfile1.json", nodeId: 4 },
{ label: "abc1_jsonfile2.json", nodeId: 5 },
{ label: "abc1_textfile1.txt", nodeId: 6 },
{ label: "abc1_textfile2.txt", nodeId: 7 },
{
label: "abc2",
nodeId: 8,
child: [
{ label: "abc2_jsonfile.json", nodeId: 12 },
{
label: "abc3",
nodeId: 13,
child: [
{ label: "abc3_jsonfile.json", nodeId: 14 },
{ label: "abc3_textfile.txt", nodeId: 15 },
],
},
],
},
{
label: "abc2_2",
nodeId: 9,
child: [
{ label: "abc2_2_jsonfile.json", nodeId: 10 },
{ label: "abc2_2_textfile.txt", nodeId: 11 },
],
},
],
},
{
label: "def1",
nodeId: 16,
child: [
{ label: "def_jsonfile1.json", nodeId: 17 },
{ label: "def_jsonfile2.json", nodeId: 18 },
{ label: "def_textfile1.txt", nodeId: 19 },
{ label: "def_textfile2.txt", nodeId: 20 },
],
},
{
label: "ghi1",
nodeId: 21,
child: [
{
label: "ghi2",
nodeId: 22,
child: [
{ label: "ghi2_jsonfile1.json", nodeId: 23 },
{ label: "ghi2_jsonfile2.json", nodeId: 24 },
{ label: "ghi2_textfile1.txt", nodeId: 25 },
{ label: "ghi2_textfile2.txt", nodeId: 26 },
],
},
],
},
{ label: "jsonfile1.json", nodeId: 27 },
{ label: "jsonfile2.json", nodeId: 28 },
{ label: "textfile1.txt", nodeId: 29 },
{ label: "textfile2.txt", nodeId: 30 },
],
},
],
},
],
},
],
}
const TreeViewExample2 = () => {
const [treeInfo, setTreeInfo] = useState({});
/*
let tmpTreeInfo = {};
let nodeId = 0;
const appendChild = (arr, info) => {
if (arr.child === undefined) arr.child = [];
if (arr.child.findIndex((item) => item.label === info) === -1) {
arr.child.push({ label: info, nodeId });
nodeId++;
}
};
const makeDirectories = (directories) => {
tmpTreeInfo = {};
for (let d of directories) {
let split = d.split("/");
let len = split.length;
let current = tmpTreeInfo;
for (let i = 0; i < len; i++) {
appendChild(current, split[i]);
current = current.child.find((item) => item.label === split[i]);
}
}
console.log(tmpTreeInfo);
setTreeInfo(tmpTreeInfo);
};
*/
const getFiles = () => {
setTreeInfo(localData);
return;
// let server = `http://192.168.55.120:3002`;
// let path = `D:\\github\\globfiles\\**`;
// fetch(`${server}/useGlob?path=${path}`)
// .then((res) => res.json())
// .then((data) => makeDirectories(data.findPath));
};
const makeTreeItem = (info, parent) => {
if (info.child === undefined) return;
return info.child.map((item, idx) => (
<TreeItem
key={idx}
nodeId={item.nodeId.toString()}
label={item.label}
onClick={() => console.log(`${parent}/${item.label}`)}
>
{makeTreeItem(item, `${parent}/${item.label}`)}
</TreeItem>
));
};
useEffect(() => {
getFiles();
}, []);
return (
<div>
{/* <button onClick={getFiles}>test</button> */}
<TreeView
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
//sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
{makeTreeItem(treeInfo, "")}
</TreeView>
</div>
);
};
export default TreeViewExample2;
const TreeViewExample2 = () => {
const [treeInfo, setTreeInfo] = useState({});
const [expanded, setExpanded] = React.useState([]);
const [selected, setSelected] = React.useState([]);
먼저 예시에서 주어진 메서드를 그대로 붙여넣자.
const handleToggle = (event, nodeIds) => {
setExpanded(nodeIds);
};
const handleSelect = (event, nodeIds) => {
setSelected(nodeIds);
};
const handleExpandClick = () => {
setExpanded((oldExpanded) =>
oldExpanded.length === 0 ? ['1', '5', '6', '7'] : [],
);
};
const handleSelectClick = () => {
setSelected((oldSelected) =>
oldSelected.length === 0 ? ['1', '2', '3', '4', '5', '6', '7', '8', '9'] : [],
);
};
버튼을 추가하고, expanded, selected, onNodeToggle, onNodeSelect를 추가한다.
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
...
return (
<div>
{/* <button onClick={getFiles}>test</button> */}
<Box sx={{ mb: 1 }}>
<Button onClick={handleExpandClick}>
{expanded.length === 0 ? 'Expand all' : 'Collapse all'}
</Button>
<Button onClick={handleSelectClick}>
{selected.length === 0 ? 'Select all' : 'Unselect all'}
</Button>
</Box>
<TreeView
expanded={expanded}
selected={selected}
onNodeToggle={handleToggle}
onNodeSelect={handleSelect}
aria-label="file system navigator"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
//sx={{ height: 240, flexGrow: 1, maxWidth: 400, overflowY: "auto" }}
>
{makeTreeItem(treeInfo, "")}
</TreeView>
</div>
);
예시에서 주어지는 expanded는 1, 5, 6, 7 node만 펼친다.
oldExpanded.length === 0 ? ['1', '5', '6', '7'] : [],
여기에서는 nodeId로 전체 노드 개수를 알 수 있다.
let tmpTreeInfo = {};
let nodeId = 0;
const appendChild = (arr, info) => {
if (arr.child === undefined) arr.child = [];
if (arr.child.findIndex((item) => item.label === info) === -1) {
arr.child.push({ label: info, nodeId });
nodeId++;
}
};
그러나 실제 node와 연동하지는 않고, localData를 보고 경로를 만들고 있다.
localData에서 nodeId가 가장 큰 값은 30이다.
let localData = {
child: [
...
},
{ label: "jsonfile1.json", nodeId: 27 },
{ label: "jsonfile2.json", nodeId: 28 },
{ label: "textfile1.txt", nodeId: 29 },
{ label: "textfile2.txt", nodeId: 30 },
],
},
],
},
],
},
],
};
따라서 handleExpandClick을 다음과 같이 수정한다.
참고로 expanded에 들어갈 배열은 문자열이어야 한다.
const handleExpandClick = () => {
let fullExpanded = [];
for(let i = 0; i <= 30; i++) fullExpanded.push(i.toString());
setExpanded((oldExpanded) =>
oldExpanded.length === 0 ? fullExpanded : []
);
};
이제 버튼을 누르면 정상적으로 동작하는 것을 알 수 있다.
SELECT ALL는 기존에 정의된 노드가 모두 클릭되는 것을 알 수 있다.
결과는 링크에서 확인하자.
반응형
댓글