본문 바로가기
코딩 정보/React

[React] 효율적인 코드 작성을 위한 개념

by 꽁이꽁설꽁돌 2024. 6. 26.
728x90
반응형

목차

     

    Fragment

    자바스크립트는 한 값만 반환이 가능하기 때문에 return할때 묶어주어야 한다.

    그렇게 되면 묶기위해 불필요한 div를 써야하는데 그 대신 react의 fragment를 사용할 수 있다.

     

    import { Fragment } from "react";
    import ButtonList from "./ButtonList";
    
    function Lecture2() {
      return (
        <Fragment>
          <div>hello world</div>
          <ButtonList>dkdk</ButtonList>
        </Fragment>
      );
    }
    
    export default Lecture2;

     

    아래 코드를 쓰면 fragment 조차 사용하지 않아도 된다.

    import ButtonList from "./ButtonList";
    
    function Lecture2() {
      return (
        <>
          <div>hello world</div>
          <ButtonList>dkdk</ButtonList>
        </>
      );
    }
    
    export default Lecture2;

     

    리액트의 동일한 구조 묶어서 효율적으로 코드 작성하기

    import React from "react";
    import { useState } from "react";
    import Section from "./Section";
    const buttons = ["css", "html", "js"];
    
    function ButtonList({ children }) {
      const [message, setMessage] = useState("first");
    
      function clickEvent(message) {
        setMessage(message);
      }
      //이벤트에 함수 전달할때 clickEvent()로 전달하면 함수가 바로 실행됨
      //따라서 함수명을 전달해주어야 함
      return (
        <div>
          <h2> {children}</h2>
    
          {buttons.map((item, index) => (
            <button onClick={() => clickEvent(item)} type="button" key={index}>
              {item}
            </button>
          ))}
          {message}
        </div>
      );
    }
    
    export default ButtonList;

     

    export default function CoreConcepts(){
        return <div>
            <h2>Core Concepts</h2>
    		contents
        </div>
    }

     

    이런식의 구조로 만들어 묶어줄 수 있다.

    또한 ...props를 넣어주었는데 각각의 컴포넌트에 맞는 classname, id를 넣는 것이 번거로움으로

    이렇게 써주면 알아서 들어가게 된다.

    
    function Section({title, children, ...props}){
        return(
            <section {...props}>
                <h2>{title}</h2>
                {children}
            </section>
        )
    }
    
    export default Section;

     

     

    아래는 위 코드를 이용한 모습이다.

    className이 각각의 컴포넌트에 적용되는 것을 알 수 있다.

    import Section from "./Section";
    import "./CoreConcepts.css";
    function CoreConcepts() {
      return (
        <Section className="conceptTitle" title={"concept1"}>
          {" "}
          contents
        </Section>
      );
    }
    export default CoreConcepts;
    import React from "react";
    import { useState } from "react";
    import Section from "./Section";
    import "./ButtonList.css";
    const buttons = ["css", "html", "js"];
    
    function ButtonList({ children }) {
      const [message, setMessage] = useState("first");
    
      function clickEvent(message) {
        setMessage(message);
      }
      //이벤트에 함수 전달할때 clickEvent()로 전달하면 함수가 바로 실행됨
      //따라서 함수명을 전달해주어야 함
      return (
        <Section title={children}>
          {buttons.map((item, index) => (
            <button
              className="button"
              onClick={() => clickEvent(item)}
              type="button"
              key={index}
            >
              {item}
            </button>
          ))}
          {message}
        </Section>
      );
    }
    
    export default ButtonList;

     

    슬롯만들기

    아래코드의 구조를 더 간결화 시킬 수 있다.

    import CoreConcepts from "./CoreConcepts";
    import ButtonList from "./ButtonList";
    import Tabs from "./Tabs";
    function Head() {
      return (
        <>
          <CoreConcepts></CoreConcepts>
          <menu>
          <ButtonList>ff</ButtonList>
          </menu>
          contents
    
        </>
      );
    }
    
    export default Head;

     

    Tabs 컴포넌트를 만들어 준 뒤 buttons를 추가한다.

    function Tabs({ children, buttons }) {
      return (
        <>
          <menu>{buttons}</menu>
          {children}
        </>
      );
    }
    export default Tabs;

     

    {}안에는 리턴값이 하나만 와야한다. 

    아래코드에서는 하나였지만 만약 둘이상인 경우에는 <></>나 fragment를 통해 묶어주자

    import CoreConcepts from "./CoreConcepts";
    import ButtonList from "./ButtonList";
    import Tabs from "./Tabs";
    function Head() {
      return (
        <>
          <CoreConcepts></CoreConcepts>
          <Tabs buttons={<ButtonList>ff</ButtonList>}>탭</Tabs>
        </>
      );
    }
    
    export default Head;

     

    컴포넌트 타입의 동적 설정

    이런식으로 html속성을 프롭스로 전달 받아 바꿀 수 있다.

    커스텀 컴포넌트이기 때문에 ButtonsContainer과 같이 대문자로 시작해 주어야 한다.

     

    또한 아래와 같이 기본적으로 menu를 할당해 줌으로써 기본값을 설정해 줄 수 있다.

    function Tabs({ children, buttons, ButtonsContainer = "menu" }) {
      return (
        <>
          <ButtonsContainer>{buttons}</ButtonsContainer>
          {children}
        </>
      );
    }
    export default Tabs;

     

    아래와 같이 코드를 작성하면 menu로 html속성이 바뀐 것을 볼 수 있다.

    import CoreConcepts from "./CoreConcepts";
    import ButtonList from "./ButtonList";
    import Tabs from "./Tabs";
    function Head() {
      return (
        <>
          <CoreConcepts></CoreConcepts>
          <Tabs ButtonsContainer={"menu"} buttons={<ButtonList>ff</ButtonList>}>contents</Tabs>
        </>
      );
    }
    
    export default Head;

     

    또한 이런식으로 내가 만든 커스텀 컴포넌트를 할당시킬 수 있다.

    import CoreConcepts from "./CoreConcepts";
    import ButtonList from "./ButtonList";
    import Section from "./Section";
    import Tabs from "./Tabs";
    function Head() {
      return (
        <>
          <CoreConcepts></CoreConcepts>
          <Tabs ButtonsContainer={Section} buttons={<ButtonList>ff</ButtonList>}>contents</Tabs>
        </>
      );
    }
    
    export default Head;

     

    React 상태 업데이트 시 주의점

    상태 변경 시에는 이전 상태값에 기반하여 변경하려면 함수형태를 써주어야 한다.

     <PlayerEditButton
            onClick={() => {
              setEdit(!edit);  //잘못된 형식
              setEdit((edit) => !edit);  //올바른 형식
            }}
          >
          
          
      
      // 이렇게 하면 예상과 다르게 상태가 변경된다.
      //둘다 시작 시점의 값을 가지기 때문에 변경이 되는 것
      <PlayerEditButton
            onClick={() => {
              setEdit(!edit);
              setEdit(!edit);
            }}
          >
    반응형