티스토리 뷰


Passing Props

 

Props

  • 부모 컴포넌트에서 자식 컴포넌트에게 Props를 전달할 때 자식 컴포넌트에서 부모에게 받은 Props의 타입을 객체 타입 지정한 것과 동일하게 지정해 주면 된다
  • Props가 많아질 경우, 타입 부분도 길어지므로 간결하게 표시하기 위해 type 또는 interface를 사용하여 Props 타입을 객체형식으로 선언해 주고 Props type 부분에 타입을 정의해 놓은 type 또는 interface를 넣어주면 된다
import { useState } from "react";

function Parent() {
  const [count, setCount] = useState("");
  return <Child count={count}></Child>;
}

type Props = {
  count: string;
};

function Child({ count }: Props) {
  return <div>{count}</div>;
}

export default Parent;


// type을 선언하지 않은 경우
function Child({ count, double, id, des } : {count:string, double:string, id:string, des:string}) {
 return <div>{count}</div>;
 }

 

 

SetState_1

  • setTodos 함수의 타입을 직접적으로 명시하는 경우
  • useState는 todo배열 타입으로 명시되어 있다
  • setTodos를 Props로 자식 컴포넌트에게 전달할 경우 useState의 setTodos에 마우스를 올리면 타입을 알 수 있으며, 그대로 복사하여 사용하면 된다
import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

function App() {
  const [todos, setTodos] = useState<Todo[]>([]);
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} setTodos={setTodos} />
      ))}
    </>
  );
}

function Todo({
  id,
  setTodos,
}: {
  id: string;
  setTodos: React.Dispatch<React.SetStateAction<Todo[]>>;
}) {
  const deleteTodo = () => {
    setTodos((prev) => prev.filter((todo) => todo.id !== id));
  };

  return <div onClick={deleteTodo}></div>;
}

export default App;

 

 

SetState_2

  • setTodos 함수의 콜백함수를 넣어준 경우
  • setTodos 함수의 인자로 Todos[ ]을 반환하는 콜백 함수를 넣어준다 ( (prev) => prev.filter((todo) => todo.id !== id) <= 이 부분이 인자로 들어가는 것) 
  •   setTodos 함수의 반환값이 없을 경우 void로 만들어준다(등록 외 수정, 삭제는 반환값이 없다)
setTodos 함수의 인자로 전달되는 콜백 함수
1. setTodos 함수의 인자로 전달되는 콜백 함수는 이전 상태를 받아서 새로운 상태를 반환한다
2. prev는 이전 상태를 받아와서 변경된 상태를 반환하는 것으로  prev는 이전 상태인 Todos[ ] 배열을 나타낸다
3. prev.filter((todo) => todo.id !== id) 은 이전 상태에서 조건을 만족하는 항목을 필터링한 배열을 반환하는 것

콜백 함수에서 Todos[ ]을 반환하는 이유
1. 콜백 함수가 반환하는 값은 변경된 상태의 Todos [ ] 이다
2. 반환된 배열은 변경된 상태를 나타내므로, setTodos 함수가 새로운 상태로 업데이트할 때 사용된다(수정, 삭제)
import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

function App() {
  const [todos, setTodos] = useState<Todo[]>([]);
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} setTodos={setTodos} />
      ))}
    </>
  );
}

function Todo({ id, setTodos }: { id: string; setTodos: (cb:(todo:Todo[])=> Todo[]) => void }) {
  const deleteTodo = () => {
    setTodos((prev) => prev.filter((todo) => todo.id !== id));
  };

  return <div onClick={deleteTodo}></div>;
}

export default App;

 

 

SetState_3

  • setTodos 함수의 콜백함수를 넣어준 경우 2
  • Todos [ ]을 props로 받아 setTodos 함수의 매개변수 타입으로 넣어준다
  • 콜백함수를 할당한 변수를 setTodos 함수에 인자로 넘겨주면 상태를 변경하게 된다
import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

function App() {
  const [todos, setTodos] = useState<Todo[]>([]);
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} todos={todos} setTodos={setTodos} />
      ))}
    </>
  );
}

function Todo({
  id,
  todos,
  setTodos,
}: {
  id: string;
  todos: Todo[];
  setTodos: (todoList: Todo[]) => void;
}) {
  const deleteTodo = () => {
    const newTodos = todos.filter((todo) => todo.id === id);
    setTodos(newTodos);
  };

  return <div onClick={deleteTodo}></div>;
}

export default App;

 

 

SetState_4

  • 부모 컴포넌트에서 함수를 props로 전달받은 경우
  • 부모 컴포넌트에서 id를 인자로 받아 Todos[ ] 의 값을 변경하는 함수를 작성한다
  •  자식 컴포넌트는 Todos[ ] 변경 함수와 인자인 id props로 받고, OnClick 함수 실행 부분에 props로 받은 함수에 인자를 넣어주면 된다
import { useState } from "react";

type Todo = {
  id: string;
  isDone: boolean;
};

function App() {
  const [todos, setTodos] = useState<Todo[]>([]);

  const deleteTodo = (id: string) => {
    const newTodos = todos.filter((todo) => todo.id === id);
    setTodos(newTodos);
  };
  return (
    <>
      {todos.map(({ id }) => (
        <Todo key={id} id={id} deleteTodo={deleteTodo} />
      ))}
    </>
  );
}

function Todo({
  id,
  deleteTodo,
}: {
  id: string;
  deleteTodo: (id: string) => void;
}) {
  const handleOnClick = () => {
    deleteTodo(id);
  };
  return <div onClick={handleOnClick}></div>;
}

export default App;

Children Props

부모 컴포넌트보다 자식 컴포넌트가 먼저 정의되어야 하기 때문에 부모컴포넌트는 가장 아래에 있다

 React.FC

  • React 18 버전 이전
  • 부모컴포넌트는 BaseType의 id를 Child 컴포넌트로 전달
  • 자식컴포넌트는 React.FC <BaseType (제네릭) > 타입을 넣어주어  부모 컴포넌트에서 받은 id의 타입을 정의해 준다
  • 부모컴포넌트에서 자식 컴포넌트에게 props 전달 시, 명시적이지 않고, 가독성이 좋지 않아 18 버전 이후 변경됨. 하지만 아직 사용하는 기업이 있을 수 있기 때문에 사용법은 알아두는 게 좋다
type BaseType = {
  id: string;
};

const Child: React.FC<BaseType> = ({ id }) => {
  return <div>{id}</div>;
};

//React 18버전 이전
export function Parent() {
  return (
    <Child id="">
      <div>has children</div>
    </Child>
  );
}

 

PropsWithChildren

  • 부모컴포넌트에서 자식 컴포넌트 사이에 children을 입력해 자식 컴포넌트한테 전달한다
  • 자식컴포넌트는 Children에 PropsWithChildren <BaseType (제네릭)>으로 타입을 명시해 제네릭타입의 Children를 사용할 수 있다
  • 부모컴포넌트에서 children을 전달하지 않아도 자식 컴포넌트는 오류가 생기지 않기 때문에 명시적이지 않다는 단점이 있다
import { PropsWithChildren } from "react";

type BaseType = {
  id: string;
};

function Child({ children }: PropsWithChildren<BaseType>) {
  return <div>{children}</div>;
}

// 1. children을 전달한 경우
export function Parent() {
  return <Child id="">
  <div>children</div>;
  </Child>;
}

// 2. children을 전달하지 않은 경우
export function Parent() {
  return <Child id=""></Child>;
}

 

 

Children을 타입으로 명시하는 방법

  • 제네릭 타입의 StrictChildren <T>를 선언하고 속성으로 T + Children객체는 무조건 리액트 노드 타입이라고 명시해 준다
  • 부모 컴포넌트는 자식 컴포넌트 안에 Children을 감싸 자식 컴포넌트한테 전달한다
  • 자식 컴포넌트는 Children을 제네릭 타입의 StrictChildren 타입으로 명시해 주고 T의 매개변수는 부모 컴포넌트가 전달한 데이터 타입이 들어가므로  id 프로퍼티를 포함하는 객체의 타입을 넣어주면 된다
  • 부모 컴포넌트에서 자식 컴포넌트한테 값을 전달하지 않은 경우 오류가 발생한다
import { ReactNode } from "react";

type BaseType = {
  id: string;
};

type StrictChildren<T> = T & { children: ReactNode };

function Child({ children }: StrictChildren<BaseType>) {
  return <div>{children}</div>;
}

export function Parent() {
  return (
    <Child id="">
      <div>chlidren</div>
    </Child>
  );
}

Generic, Utility Type 통해서 Props용 Type 만들기

부모컴포넌트와 자식 컴포넌트의 파일이 다른 경우

import {
  AddressComponent,
  PersonChildComponent,
  ProfileComponent,
} from "./UtilityTypeChildren";

export type PersonProps = {
  id: string;
  description: string;
  address: string;
  age: number;
  profile: string;
};

export const PersonComponent = ({
  id,
  description,
  address,
  age,
  profile,
}: PersonProps) => {
  return (
    <>
     // PropsWithChildren
      <PersonChildComponent>
        <div>{id}</div>
      </PersonChildComponent>
      
      // Omit
      <ProfileComponent
        description={description}
        address={address}
        age={age}
        profile={profile}
      />
      
      // Pick
      <AddressComponent address={address} />
    </>
  );
};
import { PropsWithChildren, ReactNode } from "react";
import { PersonProps } from "./UtilityType";

export const PersonChildComponent = ({ children }: PropsWithChildren) => {
  return <>{children}</>;
};

};import { PropsWithChildren, ReactNode } from "react";
import { PersonProps } from "./UtilityType";

// Children
export const PersonChildComponent = ({ children }: PropsWithChildren) => {
  return <>{children}</>;
};

// Omit
type OmitType = Omit<PersonProps, "id">;

export const ProfileComponent = ({
  description,
  address,
  age,
  profile,
}: OmitType) => {
  return <></>;
};

// Pick
type PickType = Pick<PersonProps, "address">;

export const AddressComponent = ({ address }: PickType) => {
  return <></>;
};

 

PropsWithChildren

  • PersonChildComponent 컴포넌트는 PersonComponent 컴포넌트에서 전달받은 값을 PropsWithChildren에 제네릭 타입을 넣어주지 않고 값을 받아도 Children을 추가해 줄 수 있으나 제네릭 타입을 추가해 주면 가독성이 좋아진다

Omit

  • PersonComponent 가 받은 props 중 일부를 빼야 할 경우
  • ProfileComponent 컴포넌트는 사용하지 않는 props(속성)를 선택하여 새로운 타입을 생성하여 사용한다
  • 부모 컴포넌트인 PersonComponent 이 받은 type에서 속성을 제외하여 사용하는 것

Pick

  • PersonComponent 가 받은 props 중 일부만 사용하는 경우
  • AddressComponent 컴포넌트는 사용하는 props(속성)를 선택하여 새로운 타입을 생성하여 사용한다
  • 부모 컴포넌트인 PersonComponent 이 받은 type에서 속성을 선택하여 사용하는 것

Event Handler 사용하기( 이벤트 타입 확인하는 방법 )

  1.  <div onClick = {(e) => { }}>{counter}</div> 으로 작성 후 e에 마우스를 올리면 이벤트 타입을 확인할 수 있으며, 그대로 복사해 이벤트 타입을 넣어주면 된다
  2. onClick에 마우스를 올리면 이벤트를 확인할 수 있다 (ex . MouseEvent) 확인한 이벤트를 리액트에서 가져오고( MouseEvent 입력하면 우측에 react라고 회색 글씨가 나옴 그거 선택) 제네릭 타입엔 이벤트 타입을 사용하는 요소(div)를 넣어주면 된다
import { useState } from "react";

function App() {
  const [counter, setCounter] = useState<number>(1);
  const eventHandler = (e: React.MouseEvent<HTMLDivElement>) => {};
  return <div onClick={eventHandler}>{counter}</div>;
}

export default App;
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함