공부기록/Typescript

useState / Formevent /setState / useRef 타입지정

Jenner 2023. 11. 15. 16:22

 

 

 

state 의 Type

 


 

1. array타입

 

CourseGoal 유형을 가지는 array 타입 설정

 

 

 

type CourseGoal = {
  title: string;
  description: string;
  id: number;
};

const App = () => {
  const [goals, setGoals] = useState<CourseGoal[]>([]);
  const [title, setTitle] = useState("");
  const [description, setDescription] = useState("");

 

 

 

2. props에 특정 이름으로 가져온 array 타입정의

 

 

import React from "react";
import CourseGoal from "./CourseGoal";

type CourseGoal = {
  goals: {
    title: string;
    description: string;
    id: number;
  }[];
};

const CourseGoalList = ({ goals }: CourseGoal) => {
  return (
    <ul>
      {goals.map((goal) => (
        <li style={{ listStyle: "none" }} key={goal.id}>
          <CourseGoal
            id={goal.id}
            title={goal.title}
            description={goal.description}
          />
        </li>
      ))}
    </ul>
  );
};

export default CourseGoalList;

 

 

3. type export / import하기 

 

중복하지 말고 export/ import 사용해보자.

 

컴포넌트와 동일한 이름이면 type이란 데코레이터를 붙여도 안된다.

이럴 땐 별칭을 할당하자

 

import React from "react";
import CourseGoal from "./CourseGoal";
import { CourseGoal as typeCoal } from "../App";

type CourseGoal = {
  goals: typeCoal[];
};

const CourseGoalList = ({ goals }: CourseGoal) => {
  return (
    <ul>
      {goals.map((goal) => (
        <li style={{ listStyle: "none" }} key={goal.id}>
          <CourseGoal
            id={goal.id}
            title={goal.title}
            description={goal.description}
            // setGoals={setGoals}
          />
        </li>
      ))}
    </ul>
  );
};

export default CourseGoalList;

 

 

 

 

 

 

 

event의 Type


 

Form Event의 관련 타입지정 

(해당 이벤트가 발생하는 HTML요소의 타입)

 

 

  const handleAddGoal = (e: FormEvent) => {
    e.preventDefault();

    new FormData(e?.currentTarget)

 

 

FormEvent에서 currentTarget을 가져오려면 

에러가 발생하므로 

event가 발생하는  HTML요소 타입을 지정해 줘야 함.

 

 

Form Event의 관련 타입은

HTML element 또는 HTML element의 type

 

올바른 타입을 지정하기 위해서

HTMLForm이벤트를 지정해줌

 

 

const handleAddGoal = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

 

 

 

 

useState를 활용하여 form 업데이트 하기 setState의 Type


 

setState를 자식 컴포넌트에서 받아 직접 조작해줌.

받을 때는 아래의 경우 setGoals의 타입을 지정

 

강의 에서 나오지 않았지만

아래는 찾아서 입력 해본 결과 

 

import { type FormEvent, useState } from "react";
import { CourseGoal } from "../App";

interface NewGoalProps {
  setGoals: React.Dispatch<React.SetStateAction<CourseGoal[]>>;
}

const NewGoal: React.FC<NewGoalProps> = ({ setGoals }) => {
  const [title, setTitle] = useState("");
  const [description, setDescription] = useState("");

  const handleAddGoal = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();

    new FormData(e?.currentTarget);
    setGoals((prev: CourseGoal[]) => [
      ...prev,
      {
        title,
        description,
        id: prev.length + Math.floor(Math.random() * 10000),
      },
    ]);

    setTitle("");
    setDescription("");
  };

  return (
    <form onSubmit={handleAddGoal}>
      <label htmlFor="title" />
      <input
        id="title"
        type="text"
        onChange={(e) => {
          setTitle(e.target.value);
        }}
        value={title}
      />
      <label htmlFor="description" />
      <input
        id="description"
        type="text"
        onChange={(e) => {
          setDescription(e.target.value);
        }}
        value={description}
      />
      <button type="submit">Add Goal</button>
    </form>
  );
};

export default NewGoal;

 

 

 

개인적인 이해  (틀릴수 있음주의)

 

  setGoals: React.Dispatch<React.SetStateAction<CourseGoal[]>>

라고 지정해줘야 setGoals를 문제없이 쓸 수 있었음 

 

 

 

 

 

 

setGoals는 

함수인데, A라는 제네릭타입을 받아 아무것도 리턴하지 않는 함수

type React.Dispatch<A> = (value: A) => void

 

 

A라는 제네릭타입

React.SetStateAction이라는 타입 

 

그 타입은 

type React.SetStateAction<S> = S | ((prevState: S) => S)

 

 

S라는 제네릭 타입을 받아 넣거나,

S타입인 prevState를 받아 S라는 타입을 return해주는 타입

 

 

 

S라는 제네릭 타입은 무엇이냐? 

내가 지정해 주어 import해준 타입

해당 속성을 객체로 가지고 있는 arrray타입

 

 

(alias) type CourseGoal = {
    title: string;
    description: string;
    id: number;
}
import CourseGoal

 

 

 

 

 

 

useRef 의 Type


 

useRef를 활용하여 돔의 value에 접근 하기 

 

 

import { type FormEvent, useRef } from "react";

const NewGoal = () => {
  const goal = useRef();
  const description = useRef();

  const handleAddGoal = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
  };

  return (
    <form onSubmit={handleAddGoal}>
      <label htmlFor="title" />
      <input id="title" type="text" ref={goal} />
      <label htmlFor="description" />
      <input id="description" type="text" ref={description} />
      <button type="submit">Add Goal</button>
    </form>
  );
};

export default NewGoal;

 

 

 

 

에러 1. 

 

 

 

 

 

에러를 볼 때 가장 유용한 것은 가장 아래것들 

 

아래의 내용을 보면 current 속성의 Type이 호환불가함.

undefined는 HTMLInputElement | null타입에 할당할 수 없음.

 

 

이란 에러임 

 

이 ref는 기본 초기 값이 undefined.

이 ref는 내부적으로 

ref를 허용하지 않도록 유형이 지정됨. 

 

해결방법 


 

초기 시작값으로 null을 지정

 

 

  const goal = useRef(null);
  const description = useRef(null);

 

 

 

아무것도 넣지 않는다면 

undefined로 전혀 값이 존재하지 않음을 의미

null은 아직 값이 없음을 의미

 

 

 

 

에러 2. goal은 null이 될 수 있다!?


 

해당 값에 접근하기 위한 코드

 

그러나 goal은 null이 될 수 있다고 타입스크립트가 생각하여 에러를 줌

 

 

 

 

 

 

 

해결방법 


 

그러나 개발자는 알고있음

 

handleAddGoal이란 함수가 실행된 뒤 

값이 null이 아닌 뒤에야 접근하고 있으므로.

 

그러므로 확실히 알고있는것을 Typescirpt에게 알려줘야함 (느낌표를 붙여!)

 

 

 

에러 3. value는 type 'never'에 없어!!!


 

useRef는 초깃값에 null을 지정해 주었다.

 

그리고 함수 handleAddGoal을 실행할 때는 

input요소의 ref의 입력요소가 될 것이다. 

 

 

 

 

해결방법 : 

관련된 추가 유형정보를 전달하기

 

 

 

 

Typescript에 내장되어있으므로 import 할 필요 없음 

 

  const goal = useRef<HTMLInputElement>(null);

 

 

 

이제 Typescript는 type이 null이거나 

HTMLInputElement임을 알게 되었다.

 

 

 

그래서 모든 속성에 접근할 수 있게 됨!