본문 바로가기

Libraries/React

[React] 중복된 useState 상태 및 함수 코드 정리하기, 컴포넌트 분리하기

728x90

 

 

중복된 useState 상태 및 함수코드 정리하는 방법을 알아보자!

 

 

 

 

 만들 예제의 완성본 

 

4개의 버튼을 누르면 각각의 색깔이 연보라에서 진보라로 바뀌게 한다.

 

 

 

 

 


 

 

 

 

 1. App.js에 MbtiButton 컴포넌트를 import한다. 

 

 App.js  

import { MbtiButton } from "./MbtiButton";
import "./styles.css";

export default function App() {
  return (
    <div className="App">
      <MbtiButton />
    </div>
  );
}

 

 


 

 

 2. MbtiButton.jsx를 마크업한다. 

 

 

 MbtiButton.jsx 

import "./MbtiButton.css";
import LightPurpleE from "./assets/E-light-purple.png";
import LightPurpleI from "./assets/I-light-purple.png";
import LightPurpleP from "./assets/P-light-purple.png";
import LightPurpleJ from "./assets/J-light-purple.png";
import DeepPurpleE from "./assets/E-deep-purple.png";
import DeepPurpleI from "./assets/I-deep-purple.png";
import DeepPurpleP from "./assets/P-deep-purple.png";
import DeepPurpleJ from "./assets/J-deep-purple.png";

export const MbtiButton = () => {
  return (
    <div>
      <div className="container">
        <span className="title">MBTI BOX</span>
        <ul className="mbti-pick-box">
          <li>
            <button type="button" className="mbti-button">
              <img src={LightPurpleI} alt="MBTI I 아이콘"></img>
            </button>
          </li>
          <li>
            <button type="button" className="mbti-button">
              <img src={LightPurpleE} alt="MBTI E 아이콘"></img>
            </button>
          </li>
          <li>
            <button type="button" className="mbti-button">
              <img src={LightPurpleJ} alt="MBTI J 아이콘"></img>
            </button>
          </li>
          <li>
            <button type="button" className="mbti-button">
              <img src={LightPurpleP} alt="MBTI P 아이콘"></img>
            </button>
          </li>
        </ul>
      </div>
    </div>
  );
};

 

 


 

 

 3. 버튼을 누르면 버튼 이미지가 색깔이 바뀌게 한다. 

 

 

 

 

 MbtiButton.jsx 

import "./MbtiButton.css";
import LightPurpleE from "./assets/E-light-purple.png";
import LightPurpleI from "./assets/I-light-purple.png";
import LightPurpleP from "./assets/P-light-purple.png";
import LightPurpleJ from "./assets/J-light-purple.png";
import DeepPurpleE from "./assets/E-deep-purple.png";
import DeepPurpleI from "./assets/I-deep-purple.png";
import DeepPurpleP from "./assets/P-deep-purple.png";
import DeepPurpleJ from "./assets/J-deep-purple.png";
import { useState } from "react";

export const MbtiButton = () => {

  // 이미지 상태
  const [imageSrcI, setImageSrcI] = useState(LightPurpleI); // 이미지 초기값은 연보라
  
  // 클릭 상태 
  const [isClickedI, setIsClickedI] = useState(false); // 클릭 초기값은 false

  const [imageSrcE, setImageSrcE] = useState(LightPurpleE);
  const [isClickedE, setIsClickedE] = useState(false);

  const [imageSrcJ, setImageSrcJ] = useState(LightPurpleJ);
  const [isClickedJ, setIsClickedJ] = useState(false);

  const [imageSrcP, setImageSrcP] = useState(LightPurpleP);
  const [isClickedP, setIsClickedP] = useState(false);


  // toggle 함수 구현
  // 클릭이 false면, 이미지상태를 진보라로 바꾸고 클릭상태를 true로 바꿈
  // 클릭이 true면, 이미지상태를 연보라로 바꾸고 클릭상태를 false로 바꿈 
  const handleClickI = () => {
    if (isClickedI) {
      setImageSrcI(LightPurpleI);
      setIsClickedI(false);
    } else {
      setImageSrcI(DeepPurpleI);
      setIsClickedI(true);
    }
  };

  const handleClickE = () => {
    if (isClickedE) {
      setImageSrcE(LightPurpleE);
      setIsClickedE(false);
    } else {
      setImageSrcE(DeepPurpleE);
      setIsClickedE(true);
    }
  };

  const handleClickJ = () => {
    if (isClickedJ) {
      setImageSrcJ(LightPurpleJ);
      setIsClickedJ(false);
    } else {
      setImageSrcJ(DeepPurpleJ);
      setIsClickedJ(true);
    }
  };

  const handleClickP = () => {
    if (isClickedP) {
      setImageSrcP(LightPurpleP);
      setIsClickedP(false);
    } else {
      setImageSrcP(DeepPurpleP);
      setIsClickedP(true);
    }
  };

  return (
    <div>
      <div className="container">
        <span className="title">MBTI BOX</span>
        <ul className="mbti-pick-box">
          <li>
            <button
              type="button"
              className="mbti-button"
              onClick={handleClickI} // 클릭상태를 onClick 이벤트에 달아준다.
            >
              <img src={imageSrcI} alt="MBTI I 아이콘"></img> // 이미지상태를 img src에 달아준다.
            </button>
          </li>
          <li>
            <button
              type="button"
              className="mbti-button"
              onClick={handleClickE}
            >
              <img src={imageSrcE} alt="MBTI E 아이콘"></img> 
            </button>
          </li>
          <li>
            <button
              type="button"
              className="mbti-button"
              onClick={handleClickJ}
            >
              <img src={imageSrcJ} alt="MBTI J 아이콘"></img>
            </button>
          </li>
          <li>
            <button
              type="button"
              className="mbti-button"
              onClick={handleClickP}
            >
              <img src={imageSrcP} alt="MBTI P 아이콘"></img>
            </button>
          </li>
        </ul>
      </div>
    </div>
  );
};

 

그런데 이런식으로 코드를 작성하면, 코드가 너무 길어지는 문제점이 생긴다.

 

 


 

 

 4.  이미지 data를 따로 분리해서 만들고, <li> 부분을 컴포넌트로 분리해서 상태관리를 따로 한다. 이렇게 하면 코드가 깔끔해진다. 

 

 MbtiButton.jsx 

import { data } from "./data";
import { MbtiBox } from "./MbtiBox";
import "./MbtiButton.css";

export const MbtiButton = () => {
  return (
    <div>
      <div className="container">
        <span className="title">MBTI BOX</span>

        <div className="mbti-pick-box-container">
          <ul className="mbti-pick-box">
            {data.map((e) => {
              return <MbtiBox key={e.id} data={e} />;
            })}
          </ul>
        </div>
      </div>
    </div>
  );
};

 

 

 data.js 

import LightPurpleE from "./assets/E-light-purple.png";
import LightPurpleI from "./assets/I-light-purple.png";
import LightPurpleP from "./assets/P-light-purple.png";
import LightPurpleJ from "./assets/J-light-purple.png";
import DeepPurpleE from "./assets/E-deep-purple.png";
import DeepPurpleI from "./assets/I-deep-purple.png";
import DeepPurpleP from "./assets/P-deep-purple.png";
import DeepPurpleJ from "./assets/J-deep-purple.png";

export const data = [
  {
    id: 1,
    light_purple: LightPurpleI,
    deep_purple: DeepPurpleI,
    alt: "알파벳 I 이미지",
  },
  {
    id: 2,
    light_purple: LightPurpleE,
    deep_purple: DeepPurpleE,
    alt: "알파벳 E 이미지",
  },
  {
    id: 3,
    light_purple: LightPurpleJ,
    deep_purple: DeepPurpleJ,
    alt: "알파벳 J 이미지",
  },
  {
    id: 4,
    light_purple: LightPurpleP,
    deep_purple: DeepPurpleP,
    alt: "알파벳 P 이미지",
  },
];

 

 

 MbtiBox.jsx 

import { useState } from "react";

export const MbtiBox = ({ data }) => {  // data를 props로 받아오기

  // toggle 함수 구현, 초기값은 false 
  const [toggle, setToggle] = useState(false); 

  return (
    <li>
      <button
        type="button"
        className="mbti-button"
        onClick={() => {
          setToggle((toggle) => !toggle); // 클릭하면 toggle의 상태를 반대로 바꾼다.
        }}
      >
        <img
          src={toggle ? data.deep_purple : data.light_purple} // toggle이 true면, data의 진보라를 가져오고, false면 data의 연보라를 가져온다.
          alt={data.alt} // 대체 텍스트도 data에서 가져온다. 
        />
      </button>
    </li>
  );
};

 

 

아래와 같이 alt 값도 잘 적용된 것을 볼 수 있다.

 

 

 

728x90