Frontend/React

[React] Typescript + Inline style

khakhalog 2023. 7. 5. 16:26

원티드 프리온보딩 인턴십 1주차 과제로 사전 과제로 만든 todo list의 Best Practice를 선정하여 리팩토링하는 과제를 수행하였다.

내가 사전과제로 제출한 디자인 시스템을 따르게 되어서 나는 UI 개발(디자인 스타일링)을 맡기로 했다.

 

과제 자체가 간단했기 때문에 component도 구현할 것이 많지는 않았지만

팀원들이 css는 작성하지 않고, 스타일 관련된 props를 넘겨주는 것으로 재사용할 수 있는 component를 개발하는 것에 집중했었다.

 

elements로 Button과 InputFiled를 구현하였는데

InputFiled는 크게 입력창과 체크박스 두가지로 나누어서 개발하였고, 체크박스 구현에는 react-icons를 가져다썼었다.

 

todo 페이지

위의 이미지와 같이 할 일이 완료된 상태일 때 아이콘 색상을 바꿔주기 위해 아이콘에 style={color : #...} 와 같이 inline style을 써주니 typescript에서는 먹지 않았다.

찾아보니 typescript에서 inline style을 적용하기 위해서는 React.CSSProperties type을 명시해주어야한다고 한다.

 

이 내용을 바탕으로 아래와 같이 InputFiled 컴포넌트를 구현하였다.

import React, { forwardRef } from 'react';
import { ChangeEvent, HTMLInputTypeAttribute } from 'react';
import { MdDone } from 'react-icons/md';
import styled, { DefaultTheme } from 'styled-components';

/**
 * size : md (todo 수정 input)
 *        lr (todo 입력 input)
 *        full (로그인, 회원가입)
 * InputFiled 타입 정의
 */

interface InputProps {
  testname?: string;
  size?: 'md' | 'lr' | 'full';
  id?: string;
  type: HTMLInputTypeAttribute;
  name?: string;
  defaultChecked?: boolean;
  placeholder?: string;
  defaultValue?: string | number;
  onChange?: (e: ChangeEvent<HTMLInputElement>) => void;
}
/** 공통 색상 */
const theme: DefaultTheme = {
  checkColor: '#3DB981',
  borderColor: '#d4d4d8',
};

// inline style type 정의
const checkColor: React.CSSProperties = {
  color: theme.checkColor,
};

/** InputFiled 컴포넌트 */
export const InputField = forwardRef<HTMLInputElement, InputProps>((props, ref) => {
  if (props.type !== 'checkbox')
    return (
      <InputStyle
        data-testid={props.testname}
        size={props.size}
        id={props.id}
        type={props.type}
        name={props.name}
        defaultChecked={props.defaultChecked}
        placeholder={props.placeholder}
        defaultValue={props.defaultValue}
        onChange={props.onChange}
        ref={ref}
      />
    );
  else
    return (
      <label>
        <InputCheckBox
          data-testid={props.testname}
          size={props.size}
          id={props.id}
          type={props.type}
          name={props.name}
          defaultChecked={props.defaultChecked}
          placeholder={props.placeholder}
          defaultValue={props.defaultValue}
          onChange={props.onChange}
        />
        {props.defaultChecked ? (
          <Checked defaultChecked={props.defaultChecked}>
            <MdDone style={checkColor} />
          </Checked>
        ) : (
          <Checked />
        )}
      </label>
    );
});

const InputStyle = styled.input<InputProps>`
  width: ${props => {
    if (props.size === 'full') return `320px`;
    else if (props.size === 'md') return `220px`;
    else return `270px`;
  }};

  height: 30px;
  padding: 0px 4px;

  border: 1px solid ${theme.borderColor};
  border-radius: 0.125rem;
`;

const InputCheckBox = styled.input<InputProps>`
  display: none;
`;

const Checked = styled.div`
  width: 20px;
  height: 20px;
  border-radius: 9999px;
  border: 1px solid ${theme.borderColor};

  display: flex;
  justify-content: center;
  align-items: center;

  ${props => props.defaultChecked && `border-color : ${theme.checkColor};`}
`;

'Frontend > React' 카테고리의 다른 글

[React] React Query 톺아보기  (0) 2023.07.25
[React] Styledcomponents S-dot naming  (0) 2023.07.05
[React] Context API  (0) 2023.07.03
[React] React Router Dom V6.4  (0) 2023.05.19
[React] CSS Reset  (2) 2023.01.08