React w/ TS

Circlewee·2022년 6월 21일
0

React

목록 보기
3/3

1. Tips

1.1 Generic props

props의 interface의 중복을 최소한으로 줄이기 위한 방법

interface ListProps<T> {
  items: T[]; // Array<T>
  handleClick: () => void;
}

const List = <T extends {}>({ items, handleClick }: ListProps<T>) => {
  return (
    <ul>
      {items.map((item, index) => (
        <li key={index} onClick={handleClick}>
          {item}
        </li>
      ))}
    </ul>
  );
}
  • props를 제네릭 인터페이스로 선언
  • 함수 시그니처에서 괄호 앞에 타입 파라미터 T 선언
  • interface가 객체의 형태기 때문에 {} 객체 리터럴을 extends하는 제약 조건 추가
  • 사용 시에는 props만 전달해도 알아서 T의 타입을 추론

1.2 templete literal type

type XPosition = "left" | "center" | "right";
type YPosition = "top" | "center" | "bottom";

type TicTacToeClassName = `${XPosition}-${YPosition}`;
/* ===
type TicTacToeClassName = 
  "left-top"
  | "center-top"
  | "right=top" 
  | ... 
*/
  • templete literal 문법을 활용해 쉽게 타입을 정의할 수 있다.

1.3 다른 컴포넌트의 props를 추출

const CustomButton: React.FC<React.ComponentProps<typeof Button>> = (props) => {
  return (
    <button style={props.styles} onClick={props.handleClick}>
      {props.children}
    </button>
  );
}
  • Button component의 props type을 추출해 제네릭의 형태로 정의하면 다른 컴포넌트의 props type을 추출해 사용할 수 있다.

2. Props

2.1 in FC

export const Button = (props: React.PropsWithChildren<ButtonProps>) => {
  return <button {...props} >{props.children}</button>
}
  • React.PropsWithChildren: 제네릭에 전달한 props와 props.children을 인터섹션
  • props.children: react에서 기본적으로 전달해주는 children props(자식 노드들)

2.2 more comportable

export const Button: React.FC<ButtonProps> = (props) => {
  return <button {...props} >{props.children}</button>
}

type FC<P = {}> = FunctionComponent<P>;
  
interface FunctionComponent<P = {}> {
  (props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
}

1.3 Event props

interface ButtonProps {
  styles?: React.CSSProperties;
  handleClick: (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
}

export const Button: React.FC<ButtonProps> = (props) => {
  const buttonStyles = createButtonStyle(props.styles);
  return (
    <button style={buttonStyles} onClick={props.handleClick}>
      {props.children}
    </button>
  );
};
  • event type을 쉽게 알 수 있는 방법중 하나는 onClick={e => console.log(e)}를 해보면 된다.
  • React.CSSProperties, React.FC<>, React.MouseEvent는 모두 React에서 제공하는 type이다.

3. Hook

3.1 useState()

// 1
function useState<S>(initialState: S | (() => S)): [S, Dispatch<SetStateAction<S>>];
// 2
function useState<S = undefined>(): [S | undefined, Dispatch<SetStateAction<S | undefined>>];
  1. 초기 값이 존재하는 경우 그것으로 type을 결정
  2. 초기 값이 없다면 undefined로 설정
    여기서 초기값을 null 혹은 undefined로 주게 된다면 다른 타입의 데이터를 인자로 넘길 경우 에러가 나기때문에 useState의 제네릭 타입을 설정해준다.(Union type)
    useState<String | null>(null)

3.2 useReducer()

type ScoreState = {
  score: number;
}

type CounterAction = {
  type: "INCREMENT" | "DECREMENT";
  score: number;
}

type ResetAction = {
  type: "RESET";
}

type ScoreAction = CounterAction | ResetAction; // RESET action시 score를 받지 않는 경우를 감안해 Union으로 구성

const reducer = (state: ScoreState, action: ScoreAction): ScoreState => {
  swtich (action.type) {
    case "INCREMENT":
      return { score: state.score + action.score };
    case "DECREMENT":
      const result = state.score - action.score;
      return { score: result < 0 ? 0 : result };
    case "RESET":
      return { score: 0 };
    default:
      return state;
  }
}

export const ScoreCounter = () => {
  const [score, dispatch] = React.useReducer(reducer, { score: 0 });
  return <div>{score}</div>
}
  1. action.type에 원하는 타입만 들어올 수 있게 string union으로 type정의, reset의 경우엔 score가 필요없으므로 union으로 해결
  2. reducer 함수에 정의한 type을 제공

4. ContextAPI

interface ScoreContextValue { 
  score: number;
  dispatch: Dispatch<ScoreAction>;
}

export const ScoreContest = createContext<ScoreContextValue>({
  score: 0;
  dispatch: () => {};
});
  • 초깃값에 대한 타입을 제네릭으로 제공
profile
공부할 게 너무 많아요

0개의 댓글