본문 바로가기
항해99/실전 WIL | TIL

[TIL-011] Styled-component 동적으로 활용하기, 기술 면접 스터디 발표

by junvely 2023. 4. 22.

Today목표 : 4/21일 Styled-component 동적으로 활용하기, 기술 면접 스터디 발표


알게된 점,

 

Styled-component 파일 구조

src/
  components/
    Button/
      index.js
      Button.styles.js
    Card/
      index.js
      Card.styles.js

위 파일 구조를 참고하여 모듈화하여 styled-component를 사용하는 연습을 해야 할 것 같다.

 

Styled-component 동적으로 활용하기

Styled-component에서 동적으로 style을 변경하고 싶어 구글링을 하면서 여러가지 방법을 찾아보았다. 하지만 보통 inline 방식이거나, switch문을 사용한다거나, 삼항 연산자나 && 연산자 등 내가 원하는 답을 찾기가 너무 어려웠다.

예를들어 Button 컴포넌트를 계속해서 재사용 할 경우, button의 type에 따라 색상을 다르게 보여줄 수 있는 방법이 없을까 고민했다. 

❗1. 그러다 갑자기 생각난 것은, 객체의 key값을 이용해 value로 색상값을 주도록 하면 되지않을까? 하는 생각이었다. 따라서 다음과 같이 구현해 보았다.

function Button({ children, type, onclick }) {
  return (
    <StButton
      width={ButtonStyles.width[type]}
      bgColor={ButtonStyles.bgColors[type]}
      bgHoverColor={ButtonStyles.bgHoverColors[type]}
      onClick={onclick}
    >
      {children}
    </StButton>
  );
}

const ButtonStyles = {
  width: {
    add: "200px",
  },
  bgColors: {
    delete: "#ccc",
    done: "#64dc95",
    notYet: "#6736ed94",
  },
  bgHoverColors: {
    delete: "#696969",
    done: "#17d164",
    notYet: "#6836ed",
  },
};

const StButton = styled.button`
  width: ${(props) => props.width || "45%"};
  line-height: 40px;
  color: #fff;
  background-color: ${(props) => props.bgColor || "#bf79f8"};
  border: 1px solid;
  border-radius: 10px;
  transition: all 0.2s;

  &:hover {
    font-weight: 500;
    background-color: ${(props) => props.bgHoverColor || "#a235fc"};
  }
`;

type이 들어오는 결과값에 따라, ButtonStyles에서 해당하는 type에 맞는 key가 있다면 그 value인 색상값을 return하도록 만들었다. 그리고 그것을 컴포넌트에 props으로 전달하여 변동적으로 사용할 CSS속성을 props값으로 받도록 하고, 없을 경우는 기본 색상을 return하도록 만들었다. 

좀 더 가독성 좋게 리팩토링을 해보았다.

import styled from "styled-components";

function Button({ children, type, onClick }) {
  const buttonWidth = ButtonStyles.width[type] || "45%";
  const buttonBgColor = ButtonStyles.bgColors[type] || "#bf79f8";
  const buttonHoverBgColor = ButtonStyles.hoverBgColor[type] || "#a235fc";

  return (
    <StButton
      width={buttonWidth}
      bgColor={buttonBgColor}
      hoverBgColor={buttonHoverBgColor}
      onClick={onClick}
    >
      {children}
    </StButton>
  );
}

const ButtonStyles = {
  width: {
    add: "200px",
  },
  bgColors: {
    delete: "#ccc",
    done: "#64dc95",
    notYet: "#6736ed94",
  },
  hoverBgColor: {
    delete: "#696969",
    done: "#17d164",
    notYet: "#6836ed",
  },
};

const StButton = styled.button`
  width: ${(props) => props.width};
  background-color: ${(props) => props.bgColor};
  color: #fff;
  line-height: 40px;
  border: 1px solid;
  border-radius: 10px;
  transition: all 0.2s;

  &:hover {
    font-weight: 500;
    background-color: ${(props) => props.hoverBgColor};
  }
`;

이와 같은 방식으로 사용해서 필요한 속성값을 객체에 추가하여 유동적으로 type에 따라 style들을 변경 가능하게 만들었다.

 

❗2. 두번째로 생각한 방법은, 그냥 아예 Button컴포넌트를 호출할 때, 색상 값 등을 props으로 전달하는 것이다. 이렇게 하면 객체를 굳이 사용하지 않고 바로 색상이 props으로 적용되게 할 수 있다.

// button컴포넌트의 props으로 모든 스타일값을 전달하는 방법
<Button
          type={todo.isDone === true ? "done" : "notYet"}
          onClick={onClickToggleChange}
          bgColor={todo.isDone === true ? "#64dc95" : "#6736ed94"}
          hoverBgColor={todo.isDone === true ? "#17d164" : "#6836ed"}
        >
        
 // button.jsx
 import styled from "styled-components";

function Button({ children, type, onClick, width, bgColor, hoverBgColor }) {
  const buttonWidth = width || "45%";
  const buttonBgColor = bgColor || "#bf79f8";
  const buttonHoverBgColor = hoverBgColor || "#a235fc";

  return (
    <StButton
      width={buttonWidth}
      bgColor={buttonBgColor}
      hoverBgColor={buttonHoverBgColor}
      onClick={onClick}
    >
      {children}
    </StButton>
  );
}

const StButton = styled.button`
  width: ${(props) => props.width};
  background-color: ${(props) => props.bgColor};
  color: #fff;
  line-height: 40px;
  border: 1px solid;
  border-radius: 10px;
  transition: all 0.2s;

  &:hover {
    font-weight: 500;
    background-color: ${(props) => props.hoverBgColor};
  }
`;

이렇게 하면 props인자가 길어지지만, 따로 ButtonStyles객체를 관리하지 않아도 된다.

하지만 버튼들이 중복되는 값이 있어도 항상 일일히 전달해 주어야 한다는 점과 버튼의 스타일을 각각 다른 컴포넌트에서 주고 있기 때문에 유지보수가 어려울 것 같다는 생각이 들었다.

이에 대해 Chat GPT에게 코드 리뷰를 부탁했더니 다음과 같은 답을 얻었다.

위의 두 방법은 둘 다 상황에 따라 유용할 수 있지만, 상황에 따라 더 좋은 방법이 있을 수 있습니다.
예를 들어, 첫 번째 방법에서는 컴포넌트의 props로 스타일 관련 값을 전달할 수 있으므로, 재사용성이 높아지고 코드가 간결해질 수 있습니다. 그러나 이 방법은 모든 스타일 값을 props로 전달해야 하므로, 많은 스타일 값을 가진 컴포넌트의 경우 번거로울 수 있습니다.
두 번째 방법에서는 스타일 값들을 객체로 모아놓은 후, 컴포넌트의 타입에 따라서 해당 값을 가져와서 사용하는 방식입니다. 이 방법은 props로 전달할 필요 없이, 객체 내에 값을 정의하여 사용할 수 있으므로 코드의 재사용성이 높아집니다. 하지만, 객체 내에 많은 값들을 모아놓으면 코드의 가독성이 떨어질 수 있고, 스타일 값들을 업데이트하려면 객체 내에 있는 값을 일일이 수정해야 하므로 번거로울 수 있습니다.
더 좋은 방법이라면, 컴포넌트의 스타일 값을 props로 전달하면서도, 스타일 값을 하나의 객체에 모아놓는 방법을 사용할 수 있습니다. 이렇게 하면, 스타일 값을 props로 전달해도 코드의 재사용성이 높아지고, 스타일 값을 객체 내에서 정의하기 때문에 스타일 값을 수정하기 쉬워집니다. 이 방법을 사용하면, 스타일 값을 props로 전달하면서도 코드의 가독성을 유지할 수 있으므로, 유지보수성이 좋아집니다.

따라서 위 조언을 참고하여 모듈화해 코드를 다음과 같이 리팩토링 해 보았다. 

 

1. 일단 파일을 분리하여 styles를 모듈화하여 사용할 수 있게 만들었다. 또 버튼의 스타일 속성 별로 별도로 객체로 생성하였고, StButton도 따로 분리하여 주었다.

// Button.styles.js
import styled from "styled-components";

export const buttonWidth = {
  add: "200px",
};

export const buttonBgColor = {
  delete: "#ccc",
  done: "#64dc95",
  notYet: "#6736ed94",
};

export const buttonHoverBgColor = {
  delete: "#696969",
  done: "#17d164",
  notYet: "#6836ed",
};

export const StButton = styled.button`
  width: ${(props) => props.width || "45%"};
  background-color: ${(props) => props.bgColor || "#bf79f8"};
  color: #fff;
  line-height: 40px;
  border: 1px solid;
  border-radius: 10px;
  transition: all 0.2s;

  &:hover {
    font-weight: 500;
    background-color: ${(props) => props.hoverBgColor || "#a235fc"};
  }
`;

2. Button 컴포넌트에서 속성값을 객체의 키값을 props으로 전달하도록 하였다.

<Button
          bgColor={buttonBgColor.delete}
          hoverBgColor={buttonHoverBgColor.delete}
          onClick={onClickDeleteTodo}
        >
// button.jsx
import { StButton } from "./Button.styles";

function Button({ children, onClick, width, bgColor, hoverBgColor }) {
  return (
    <StButton
      width={width}
      bgColor={bgColor}
      hoverBgColor={hoverBgColor}
      onClick={onClick}
    >
      {children}
    </StButton>
  );
}

export default Button;

이렇게 사용했더니 Button컴포넌트가 엄청나게 간결해진 것을 볼 수 있었다. 확실히 모듈화 하여 사용하는 것이 좋긴 한 것 같다.

만약 색상 값이 변경되더라도 객체의 키값으로 접근했기 때문에 styles파일에서 한 곳에서 관리하여 변경해주면 되기 때문에 유지보수에도 용이하다.

아직도 이 방법이 가장 최선의 방법인지는 잘 모르겠다. 하지만 계속 사용하면서 다른 코드들도 경험해 보면 더 나은 방법을 찾을 수 있을 것이다.

 

 

Styled-component의 GlobalStyle 활용하기

GlobalStyle을 따로 파일에 모듈화 하여 다음과 같이 import하여 사용하면 더 좋을 것 같다.

import styled, { createGlobalStyle } from 'styled-components';

import React from 'react';

const GlobalStyle = createGlobalStyle`
  body{
    padding: 0;
    margin: 0;
  }
`;

function App() {
    return (
        <Container>
            <GlobalStyle />
            <Button success>Hello</Button>
            <Button danger>Hello</Button>
        </Container>
    );
}

...

 

 

기술면접 스터디 발표(2회차)

오늘 발표한 주제는 'React-router-dom' 이었다.

Routing에 대한 전반적인 개념과 React-router-dom을 실제로 어떻게 사용할 수 있는지, 동적 라우팅과 중첩 라우팅 방법과 활용 예제 등을 발표했다.

우선 두번째 발표지만 떨리는 건 첫 발표와 마찬가지로 똑같았다.... 대신 처음 보다 두번째 발표에서 말을 더듬는 것이 많이 줄어들었고, 속도도 첫 발표에 비해 너무 늘어지지 않게 잘 마무리 한 것 같았다. 다만 발표 때가 유튜브 영상 촬영 때 보다 더 잘한 것 같은데 안타깝게 촬영을 못해서 더 더 많이 더듬은 영상이 올라가게 됐다ㅎㅎ.. 그래도 첫 발표에 비해 2회차지만 늘어가고 있는 것을 느껴 너무 뿌듯했고, 발표 공포증도 어쩌면 계속 개선하다 보면 극복할 수 있지 않을까라는 희망을 갖게 된 것 같다.

무엇보다 발표 내용이 너무 좋다, 발표를 잘한다는 칭찬을 계속 받고 있어서 그런지 발표할 용기가 생기는 것 같아 감사한 마음이다.아무래도 좋은 평가를 받을 수 있었던 이유는 강의에서만 듣던 내용이 사용해 본 적이 없어 실제로 와닿지 않는 부분이 많은데 그 부분에 대해 실용적으로 사용할 수 있는 예제로 계속해서 설명해 드려 이해를 도와드렸기 때문인 것 같다.

커리큘럼을 소화하기도 바쁜 와중에 시간을 투자해 계속해서 스터디를 진행하고 있는데, 나름대로 내 치부와 매번 맞서고 그걸 다른 사람들에게 보여주는게 매번 너무 괴롭지만 괴로운 것 조차도 아무렇지 않은 날이 오길 바라면서 열심히 해야겠다는 생각이 들었다.

추가적으로 다른 분께서 조언 주신 부분도 있었다.

1. useNavigate에서 -1, -2 등 이전 페이지로 이동 가능하다는 부분이고

2. 중첩 라우팅에서는 상위 경로를 제외하고 하위경로만 설정해도 가능하다는 부분이었다.

중첩 라우팅 시 하위경로만 작성하는 것이 과연 가독성에 좋을까? 라는 의문이 들긴 하지만 이런 부분도 경험이 쌓이다 보면 판단이 설 것 같다. => ex) /accountPage/login => 중첩 시 하위경로는 /login만 작성

또 다음 발표 때는 좀 더 미리 준비해서 말이 꼬이거나 더 더듬지 않도록 미리 준비하면 더 좋을 것 같다.

다음 포스팅은 발표 준비를 하면서 Route에 대해 공부하고 정리한 내용이다.

 

[React] React-router-dom이란 무엇인가?

Rounting이란? : Rounting : 경로 선택, 경로 결정 : 해당하는 페이지로 이동하기 위해 새로운 URL로 서버에 요청을 하면 그 응답으로 data를 받아 새로운 페이지를 보여주는 것, 즉 해당 경로의 페이지로

junvelee.tistory.com

 

 

 

배운 점, 아쉬운 점

1. 아직도 styled-components를 동적으로 사용하는 방법에 대해 감이 많이 잡히진 않지만 계속 사용하다 보면, 더 나은 코드를 경험하다 보면 훨씬 더 나아질 것 같다. styled-components의 가장 어려운 부분을 오늘 많이 공부하게 되어 좋았다.

2. react Hooks를 사용할 때는 Hook 사용규칙을 지켜야 한다. 따라서 꼭 변수에 담아 호출해야 한다는 것을 기억하자.

3. 내일은 꼭! level2 과제를 완료하고, redux사용방법과 동적 routing을 완벽하게 사용하는 방법을 숙지해야겠다.

4. 오늘도 발표하느라 고생 많았다. 하루하루 발전하는 모습을 느끼며 더 열심히 노력하자.