상세 컨텐츠

본문 제목

React(리액트) 티키타카 18 ( rc-tree 트리 컴포넌트)

React

by e7e 2024. 12. 25. 18:19

본문

아니 또 누군가는 Tree 컴포넌트를 쓰고 싶단다.

jstree는 jquery가 필요한 jquery 플러그인이닝, React를 쓴다면 과감없잉 버릴깡?

 

rc-tree란 게 있당. 중국말 설명이 중국산인가 보당. 

아래 npmjs에 가면 api가 테이블로 정리 되어 있당.  지금은 대략 눈치껏 확인 정도만...

https://www.npmjs.com/package/rc-tree

 

아래 링크 가면, 실행 예제와 소스를 볼 수 있어, 어쩔 또 올 수 밖에 없낭? 하는 느낌이당. 

https://tree-react-component.vercel.app/demo/draggable

 

시작하면  절반이라 했던강... 밧다리 드러가장.

 

vite로 필요한 프로젝트 맹글었다 치공, 설치 들어가장.

npm i rc-tree

 

실행 모습을 보려면 어쩔! 더미 데이터가 필요하당.~~ ㅠㅠ 

key, title, children 이 기본속성 값으로 필요하당.(복사/붙여넣기 하장장) 

 

sampleData.js

const treeData = [
  {
    key: "SM",
    title: "SM 엔터테인먼트",
    children: [
      {
        key: "aespa",
        title: "에스파",
        children: [
          { key: "aespa-1", title: "닝닝" },
          { key: "aespa-2", title: "카리나" },
          { key: "aespa-3", title: "지젤" },
          { key: "aespa-4", title: "윈터" },
        ],
      },
      {
        key: "redvelvet",
        title: "레드벨벳",
        children: [
          { key: "redvel-1", title: "조이" },
          { key: "redvel-2", title: "슬기" },
          { key: "redvel-3", title: "아이린" },
          { key: "redvel-4", title: "웬디" },
          { key: "redvel-5", title: "메리" },
        ],
      },
    ],
  },
  {
    key: "YG",
    title: "YG 엔터테인먼트",
    children: [
      {
        key: "blackpink",
        title: "블랙핑크",
        children: [
          { key: "blink-1", title: "로제" },
          { key: "blink-2", title: "제니" },
          { key: "blink-3", title: "리사" },
          { key: "blink-4", title: "지수" },
        ],
      },
    ],
  },
  {
    key: "JYP",
    title: "JYP 엔터테인먼트",
    children: [
      {
        key: "itzy",
        title: "있지",
        children: [
          { key: "itzy-1", title: "예지" },
          { key: "itzy-2", title: "채령" },
          { key: "itzy-3", title: "류진" },
          { key: "itzy-4", title: "리아" },
          { key: "itzy-5", title: "유나" },
        ],
      },
    ],
  },
  {
    key: "STAR",
    title: "스타쉽 엔터테인먼트",
    children: [
      {
        key: "ive",
        title: "IVE",
        children: [
          { key: "ive-1", title: "안유진" },
          { key: "ive-2", title: "가을" },
          { key: "ive-3", title: "레이" },
          { key: "ive-4", title: "장원영" },
          { key: "ive-5", title: "리즈" },
          { key: "ive-6", title: "이서" },
        ],
      },
    ],
  },
];

export default treeData;

 

그라믄 위의 데이터를 이용하야 기본 Tree를 맹글어보당.

제공 되는 Tree 컴포넌트의 props를 잘 눈길에 발자국 찍듯이 힘을 빼고 본당.

아이콘 이미지는 귀간지러서 api를 사용해서 넣었당. 

그래야 소스 가져간 사람이 귀안케 이미지  다운로드 안받아도 되니켕

select 이벤트도 onSelect 되어 이쓰미, 기대 반 우려 반 반반핸들추가당. 

 

MyTree.jsx

import Tree from "rc-tree";
import "rc-tree/assets/index.css";
import treeData from "./sampleData";

function MyTree() {
  const handleIcon = (obj) => {
    //console.log("체킁",obj)
    let imgURL = "";
    const hypCnt = obj.pos.split("-").length;

    // 더미이미지 와 아바타 이미지 API를 괘니 사용해 봄
    if (hypCnt == 2)
      imgURL = `https://dummyimage.com/160x160/000/fff.png&text=${obj.data.key}`;
    else if (hypCnt == 3)
      imgURL = `https://dummyimage.com/160x160/000/ff0.png&text=${obj.data.key}`;
    else if (hypCnt == 4)
      imgURL = `https://api.dicebear.com/9.x/adventurer/svg?seed=${obj.title}`;

    return <img src={imgURL} width={16} height={16} />;
  };

  const handleSelect = (skey, info) => {
    console.log("체킁 1: ", skey, info.node.title);
    console.log("체킁 2: ", info);
  };

  return (
    <Tree
      treeData={treeData}
      showIcon={true}
      icon={handleIcon}
      selectable={true}
      expandAction={"click"}
      autoExpandParent={true}
      onSelect={handleSelect}
    />
  );
}

export default MyTree;

 

App.jsx

import MyTree from "./MyTree";

function App() {
  return (
    <>
      <h2>RC 카 아니랑 RC-TREE랑</h2>
      <hr />
      <MyTree />
    </>
  );
}

export default App;

 

 

실행 화면으로 시선을 도려내 보장. 난 카리나를 선택하였당.

음... 먼가 써볼까 하는 마음이 들었지만, RC 카를 사면 더 재밌을 꺼  같당.

 

분명 요기까지만 해도 만족하는 사라미 있겠지만, 경미니라면 만족하지 아니할게당.

그래서 쪼메 더 가보도록 하장.

 

MUI 와 라우터 모듈을 괘니 추카해 주장!

npm install @mui/material @emotion/react @emotion/styled
npm i react-router-dom

 

라우터 설정 해볼까낭! 초간단 설정!

 

main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.jsx";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Idol from "./Idol.jsx";

const style = {
  color: "red",
};
createRoot(document.getElementById("root")).render(
  <StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route index element={<Idol />} />
          <Route path="/:name" element={<Idol />} />
        </Route>
        <Route path="*" element={<h1 style={style}>404</h1>} />
      </Routes>
    </BrowserRouter>
  </StrictMode>
);

 

Idol 컴포넌트가 나올 자리 Outlet 설정

useNavigate  훅 이용, 값 전달도 해봄

선택여부와 children여부를 이용, leaf인 경우만 navigate

 

MyTree.jsx

import Tree from "rc-tree";
import "rc-tree/assets/index.css";
import treeData from "./sampleData";
import { Box } from "@mui/material";
import { Outlet, useNavigate } from "react-router-dom";

function MyTree() {
  const navigate = useNavigate();

  const handleIcon = (obj) => {
    //console.log("체킁",obj)

    let imgURL = "";
    const hypCnt = obj.pos.split("-").length;
    if (hypCnt == 2)
      imgURL = `https://dummyimage.com/160x160/000/fff.png&text=${obj.data.key}`;
    else if (hypCnt == 3)
      imgURL = `https://dummyimage.com/160x160/000/ff0.png&text=${obj.data.key}`;
    else if (hypCnt == 4)
      imgURL = `https://api.dicebear.com/9.x/adventurer/svg?seed=${obj.title}`;

    return <img src={imgURL} width={16} height={16} />;
  };

  const handleSelect = (skey, info) => {
    console.log("1: ", skey, info.node.title);
    console.log("2: ", info.node);
    const selNode = info.node;

    if (!selNode.selected && !selNode.children) {
      navigate(`/${selNode.title}`, { state: selNode });
    }
  };

  return (
    <Box display={"flex"} sx={{ justifyContent: "space-between" }}>
      <Tree
        treeData={treeData}
        showIcon={true}
        icon={handleIcon}
        selectable={true}
        expandAction={"click"}
        autoExpandParent={true}
        onSelect={handleSelect}
      />
      <Box sx={{ width: "50%" }}>
        <Outlet />
      </Box>
    </Box>
  );
}

export default MyTree;

 

useLocation 훅 이용, 넘겨 받은 node값 활용

괘니 mui 컴포넌트  몇개 써봄.....

값이 없을 때 곧 router index인 경우 기본값 e7e 세팅

 

Idol.jsx

import { Avatar, Box, Typography } from "@mui/material";
import React from "react";
import { useLocation } from "react-router-dom";

function Idol() {
  const location = useLocation();
  const { title = "E7E", key = "e7e" } = { ...location.state };
  console.log("체킁2: ", key);

  return (
    <Box
      display={"flex"}
      sx={{
        border: "10px groove gold",
        justifyContent: "center",
        alignItems: "center",
      }}
    >
      <Avatar
        sx={{ width: "30%", height: "30%" }}
        src={`https://api.dicebear.com/9.x/adventurer/svg?seed=${key}`}
      />
      <Typography variant="h3">{title}</Typography>
    </Box>
  );
}

export default Idol;

 

결과는? 음 디자인은 안 좋으나, 그냥 쓸만~~ (자기만족!~~ )

 

메리 크리스 마씅

 


 

이모티콘 부자는 널렸으나

이모티콘 선택  센스  초능력은 

그저 단지 소수 몇명에게만 주어졌나니...

 

그중에도 탁월한 이가 있었으니

그 사람 금수저였당.

말과 상황에 대처하는 센스는 별로였당.

 

금수저가 보내주는 스토리 있는

연속 파노라마 이모티콘이 문득 그립당.

하여간  그냥 던 던 댄스당.~~

 

 

https://www.youtube.com/watch?v=HzOjwL7IP_o

관련글 더보기