리액트 폴더구조 : 재귀적으로 컴포넌트 구조

728x90
반응형

01. 데이터 구조

const folderData = [
  {
    id: 1,
    name: "Root Folder",
    children: [
      {
        id: 2,
        name: "Sub Folder 1",
        children: [
          { id: 3, name: "File 1" },
          { id: 4, name: "File 2" }
        ]
      },
      {
        id: 5,
        name: "Sub Folder 2",
        children: [
          { id: 6, name: "File 3" }
        ]
      }
    ]
  }
];

 

02. 재귀 컴포넌트 구조

import React from 'react';

const FolderItem = ({ item }) => {
  return (
    <div>
      <div>{item.name}</div>
      {item.children && item.children.length > 0 && (
        <div style={{ marginLeft: '20px' }}>
          {item.children.map(child => (
            <FolderItem key={child.id} item={child} />
          ))}
        </div>
      )}
    </div>
  );
};

const FolderTree = ({ data }) => {
  return (
    <div>
      {data.map(folder => (
        <FolderItem key={folder.id} item={folder} />
      ))}
    </div>
  );
};

export default FolderTree;

 

03. 폴더 열림 관리 

>  state( openFolder )로 관리

> openFolder객체 : 키 =  폴더의 id / 값은  true/false

import React, { useState } from 'react';

const FolderItem = ({ item, isOpen, onToggle }) => {
  const handleClick = () => {
    onToggle(item.id);
  };

  return (
    <div>
      <div onClick={handleClick} style={{ cursor: 'pointer' }}>
        {item.name} {isOpen ? '[-]' : '[+]'}
      </div>
      {isOpen && item.children && item.children.length > 0 && (
        <div style={{ marginLeft: '20px' }}>
          {item.children.map(child => (
            <FolderItem
              key={child.id}
              item={child}
              isOpen={isOpen}
              onToggle={onToggle}
            />
          ))}
        </div>
      )}
    </div>
  );
};

const FolderTree = ({ data }) => {
  const [openFolders, setOpenFolders] = useState({});

  const handleToggle = (id) => {
    setOpenFolders(prevState => ({
      ...prevState,
      [id]: !prevState[id]
    }));
  };

  return (
    <div>
      {data.map(folder => (
        <FolderItem
          key={folder.id}
          item={folder}
          isOpen={!!openFolders[folder.id]} //!! 연산자로 boolean값으로 사용
          onToggle={handleToggle}
        />
      ))}
    </div>
  );
};

export default FolderTree;

 

04. 폴더를 닫았다가 열 때도, 기존에 열었던 특정 폴더 상태 유지

> 로컬 스토리지 ( 새로고침해도 상태 유지) --> 이걸로 선택

> 세선 스토리지에 (브라우저 세션 동안 상태 유지)

> 리코일 (persist- persist 추후)

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

const folderData = [
  {
    id: 1,
    name: "Root Folder",
    children: [
      {
        id: 2,
        name: "Sub Folder 1",
        children: [
          { id: 3, name: "File 1" },
          { id: 4, name: "File 2" }
        ]
      },
      {
        id: 5,
        name: "Sub Folder 2",
        children: [
          { id: 6, name: "File 3" }
        ]
      }
    ]
  }
];

const FolderItem = ({ item, isOpen, onToggle }) => {
  const handleClick = () => {
    onToggle(item.id);
  };

  return (
    <div>
      <div onClick={handleClick} style={{ cursor: 'pointer' }}>
        {item.name} {isOpen ? '[-]' : '[+]'}
      </div>
      {isOpen && item.children && item.children.length > 0 && (
        <div style={{ marginLeft: '20px' }}>
          {item.children.map(child => (
            <FolderItem
              key={child.id}
              item={child}
              isOpen={!!openFolders[child.id]}
              onToggle={onToggle}
            />
          ))}
        </div>
      )}
    </div>
  );
};

const FolderTree = ({ data }) => {
  const [openFolders, setOpenFolders] = useState({});

  useEffect(() => {
    // 페이지가 로드될 때 로컬 스토리지에서 상태를 불러옵니다.
    const savedState = JSON.parse(localStorage.getItem('openFolders')) || {};
    setOpenFolders(savedState);
  }, []);

  useEffect(() => {
    // 상태가 변경될 때 로컬 스토리지에 상태를 저장합니다.
    localStorage.setItem('openFolders', JSON.stringify(openFolders));
  }, [openFolders]);

  const handleToggle = (id) => {
    setOpenFolders(prevState => ({
      ...prevState,
      [id]: !prevState[id]
    }));
  };

  return (
    <div>
      {data.map(folder => (
        <FolderItem
          key={folder.id}
          item={folder}
          isOpen={!!openFolders[folder.id]}
          onToggle={handleToggle}
        />
      ))}
    </div>
  );
};

const App = () => {
  return (
    <div>
      <h1>Folder Structure</h1>
      <FolderTree data={folderData} />
    </div>
  );
};

export default App;

 

05. 데이터 새로고침 버튼

> state(folders) : 

const FolderTree = () => {
  const [openFolders, setOpenFolders] = useState({});
  const [folders, setFolders] = useState([]);

  useEffect(() => {
    const loadInitialData = async () => {
      const initialData = await fetchAndUpdateFolders();
      setFolders(initialData);
    };
    loadInitialData();
  }, []);

  useEffect(() => {
    const savedState = JSON.parse(localStorage.getItem('openFolders')) || {};
    setOpenFolders(savedState);
  }, []);

  useEffect(() => {
    localStorage.setItem('openFolders', JSON.stringify(openFolders));
  }, [openFolders]);

  const handleToggle = (id) => {
    setOpenFolders(prevState => ({
      ...prevState,
      [id]: !prevState[id]
    }));
  };

  const handleRefresh = async () => {
    const updatedData = await fetchAndUpdateFolders();
    setFolders(updatedData);
  };

  return (
    <div>
      <button onClick={handleRefresh}>Refresh Data</button>
      {folders.map(folder => (
        <FolderItem
          key={folder.id}
          item={folder}
          isOpen={!!openFolders[folder.id]}
          onToggle={handleToggle}
        />
      ))}
    </div>
  );
};

 

끝.

 

 

 

반응형