Typescript React Hooks

jangdu·2022년 10월 28일
0

typescript

목록 보기
7/16

useState

ex counter

Counter.tsx

import React, { useState } from "react";

function Counter() {
    const [count, setCount] = useState<number>(0);
    const onIncrease = () => setCount(count + 1);
    const onDecrease = () => setCount(count - 1);
    return (
        <div>
            <h1>{count}</h1>
            <div>
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>
            </div>
        </div>
    )
}
export default Counter;

App.tsx

import React from 'react';
import './App.css';
import Counter from './Counter';

function App() {
  return (
    <Counter />
  );
}

export default App;

useState를 사용 때 useState<number>() 처럼 제네릭으로 해당 상태가 어떤 타입을 가질지 설정하기만 하면 된다.

Generics를 사용하지 않아도 타입을 유추해서 안해도 ㄱㅊ

Generics을 사용해야 할 때

1. null일수도 있을 때

type Information = { name: string; description: string };
const [info, setInformation] = useState<Information | null>(null);

2. 상태의 type이 까다로운 구조를 가지는 객체나 배열일 때

type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState<Todo[]>([]);

배열의 경우 위 코드처럼 빈 배열만 넣었을 때 어떤 타입으로 이루어진 배열인지 추론할 수 없어 Generics을 명시해야한다.

물론 as를 사용해도 된다.

type Todo = { id: number; text: string; done: boolean };
const [todos, setTodos] = useState([] as Todo[]);

인풋

import React, { useState } from 'react';

type MyFormProps = {
  onSubmit: (form: { name: string; description: string }) => void;
};

function MyForm({ onSubmit }: MyFormProps) {
  const [form, setForm] = useState({
    name: '',
    description: ''
  });

  const { name, description } = form;

  const onChange = (e: any) => {

  };

  const handleSubmit = (e: any) => {

  };

  return (
    <form onSubmit={handleSubmit}>
      <input name="name" value={name} onChange={onChange} />
      <input name="description" value={description} onChange={onChange} />
      <button type="submit">등록</button>
    </form>
  );
}

export default MyForm;

e의 타입을 무슨타입으로 설정할 지 모르는 경우 any로 설정 해놓은 뒤 onChange위에 커서를 올려두면

위처럼 어떤 타입을 사용해야 맞는지 확인이 가능하다.

import React, { useState } from "react";

type MyFormProps = {
    onSubmit: (form: { name: string; description: string }) => void;
};

function MyForm({onSubmit}: MyFormProps){
    const [form, setForm] = useState({name:'', description: ''});

    const {name, description} = form;

    const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setForm({
            ...form,
            [name]: value
        })

    };

    const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();
        onSubmit(form);
        setForm({
            name: '',
            description: ''
        }); // 초기화
    }

    return(
        <form onSubmit={handleSubmit}>
            <input name='name' value={name} onChange={onChange} />
            <input name='description' value={description} onChange={onChange} />
            <button type="submit">등록</button>
        </form>
    );
}

export default MyForm;
import React from 'react';
import './App.css';
import Counter from './Counter';
import MyForm from './MyForm';

function App() {
  const onSubmit = (form: {name: string; description: string}) => {console.log(form)}
  return (
      <MyForm onSubmit={onSubmit} />
  );
}

export default App;

useReducer

counter컴포넌트를 useReducer로 사용해보면

import React, { useReducer, useState } from "react";

// action을 |로 연달아 나열
type Action = {type:'INCREASE'} | {type: 'DECRESE'};

function reducer(state: number, action: Action): number{
    switch (action.type){
        case "INCREASE":
            return state + 1;
        case "DECRESE":
            return state - 1;
        default:
            throw new Error('Unhandled action');
    }
}

function Counter() {
    const [count, dispatch] = useReducer(reducer, 0);
    const onIncrease = () => dispatch({type: 'INCREASE'});
    const onDecrease = () => dispatch({type: 'DECRESE'});

    return (
        <div>
            <h1>{count}</h1>
            <div>
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>
            </div>
        </div>
    )
}
export default Counter;

Action type은 {type:'INCREASE'} 또는 {type: 'DECRESE'}임을 명시해준다.

Reducer를 만들 때는 파라미터로 받아오는 타입과 리턴하는 타입이 같아야만한다.

액션들이 type값만 있어 상당히 간단하나, 다른 필요한 값들이 있을 경우 매우 복잡해지는데, 이부분은 reducer로 작성할 때 액션 객체 안에 무엇이 들어있는지도 자동완성을 통해 알 수 있으며 새로운 액션을 디스패치 할 때에도 타입검사를 해준다.

profile
대충적음 전부 나만 볼래

0개의 댓글