리액트의 상태관리 Hooks 함수 useState
, useReducer
를 타입스크립트로 작성하고자 한다.
useState
useState 에서 관리할 상태를 Generics 를 통해서 설정해줄 수 있다.
타입스크립트를 사용하고 있으므로 Generics 를 생략해도 값의 타입을 읽어서 보여준다.
function Counter() {
const [count, setCount] = useState<number>(0);
}
Counter.tsx
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const onIncrease = () => setCount(count + 1);
const onDecrease = () => setCount(count - 1);
return (
<div>
<h1>{count}</h1>
<div>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
</div>
);
}
export default Counter;
MyForm.tsx
이벤트 e 에 관한 타입을 모를 때는 any 로 작성해두었다가 해당 객체를 사용한 뒤 마우스를 대면 자동으로 해당 props 에 대한 타입이 뜬다.
import React, { useState } from "react";
type MyFormProps = {
onSubmit: (form: { name: string; description: string }) => void; // 결과 반환 X
};
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 // [name] 에는 name 또는 description 이 들어온다
}) // value 에는 e.target 에서 받아온 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;
App.tsx
렌더링 해줄때에는 선언된 타입이 작성되지 않으면 오류가 뜨므로 다음과 같이 props 를 작성해주면 된다.
const App: React.FC = () => {
const onSubmit = (form: { name: string; description: string }) => {
console.log(form);
}
return <MyForm onSubmit={onSubmit} />
}
useReducer
타입스크립트로 useReducer 를 사용할 때에는 action
에 관한 타입을 type Action = |
으로 연달아서 나열하여서 사용한다.
reducer 함수를 구현할 때 action
의 타입으로 action
에 관한 타입을 정리해주었던 Action
을 작성해주면 된다.
그러면 useReducer 함수에서 type
을 작성할 때에도 자동완성으로 작성되어 실수를 방지할 수 있다.
action 이 아니더라도 들어올 값의 타입을 type xx = { } 식으로 정리를 해두면 받아오는 값의 타입을 작성하기에 좋다.
Counter.tsx
import React, { useReducer } from 'react';
type Action = { type: 'INCREASE' } | { type: 'DECREASE' }; // 이렇게 액션을 | 으로 연달아서 쭉 나열하세요.
function reducer(state: number, action: Action): number {
switch (action.type) {
case 'INCREASE':
return state + 1;
case 'DECREASE':
return state - 1;
default:
throw new Error('Unhandled action');
}
}
function Counter() {
const [count, dispatch] = useReducer(reducer, 0);
const onIncrease = () => dispatch({ type: 'INCREASE' }); // type: '' 자동완성 미리보기가 뜬다.
const onDecrease = () => dispatch({ type: 'DECREASE' });
return (
<div>
<h1>{count}</h1>
<div>
<button onClick={onIncrease}>+1</button>
<button onClick={onDecrease}>-1</button>
</div>
</div>
);
}
export default Counter;
ReducerSample.tsx
reducer 함수에서는 반환할 타입을 State 타입을 반환해야만 오류가 뜨지 않는다.
import React, { useReducer } from "react";
type Color = 'red' | 'orange' | 'yellow';
type State = {
count: number;
text: string;
color: Color;
isGood: boolean;
};
type Action =
| { type: 'SET_COUNT'; count: number }
| { type: 'SET_TEXT'; text: string }
| { type: 'SET_COLOR'; color: Color }
| { type: 'TOGGLE_GOOD'; };
function reducer(state: State, action: Action): State { // State 반환
switch (action.type) {
case 'SET_COUNT':
return {
...state,
count: action.count
}
case 'SET_TEXT':
return {
...state,
text: action.text
}
case 'SET_COLOR':
return {
...state,
color: action.color
}
case 'TOGGLE_GOOD':
return {
...state,
isGood: !state.isGood
}
default:
throw new Error('Unhandled action type');
}
}
function ReducerSample() {
const [state, dispatch] = useReducer(reducer, {
count: 0,
text: 'hello',
color: 'red',
isGood: true
});
const setCount = () => dispatch({ type: 'SET_COUNT', count: 5 });
const setText = () => dispatch({ type: 'SET_TEXT', text: 'bye' });
const setColor = () => dispatch({ type: 'SET_COLOR', color: 'orange' });
const toggleGood = () => dispatch({ type: 'TOGGLE_GOOD' });
return (
<div>
<p>
<code>count: </code> {state.count}
</p>
<p>
<code>text: </code> {state.text}
</p>
<p>
<code>color: </code> {state.color}
</p>
<p>
<code>isGood: </code> {state.isGood ? 'true' : 'false'}
</p>
<div>
<button onClick={setCount}>SET_COUNT</button>
<button onClick={setText}>SET_TEXT</button>
<button onClick={setColor}>SET_COLOR</button>
<button onClick={toggleGood}>TOGGLE_GOOD</button>
</div>
</div>
);
}
export default ReducerSample;
'Typescript' 카테고리의 다른 글
타입스크립트에서 리덕스 사용하기 - 카운터 (0) | 2021.11.21 |
---|---|
타입스크립트와 ContextAPI 활용 (0) | 2021.11.20 |
리액트 컴포넌트 타입스크립트로 작성하기 (0) | 2021.11.19 |
타입스크립트 Generics (0) | 2021.11.18 |
타입스크립트 Interface / TypeAlias (0) | 2021.11.18 |