리덕스를 리액트 환경에서 타입스크립트를 곁들여서 세팅하는 걸 처음부터 한번 해보자
우선 필요한 패키지들을 설치한다.
npm install --save @types/react-redux axios react-redux redux redux-thunk
기존에 react-redux, redux, redux-thunk, axios 까지 같다면 @types/react-redux 가 새로 추가되었다고 보면 된다.
npm 패키지 api를 이용해서 데이터를 가져와볼 건데
https://registry.npmjs.org/-/v1/search?text=react
위의 주소로 text 파라미터 뒤에 우리가 입력한 값이 들어간 패키지가 있으면 배열로서 그 데이터를 가져올 것이고 그 패키지 데이터들을 repository라고 프로젝트 내에서 부를 것이다.
그 repository를 관리할 Reducer를 만들어보면
interface RepositoriesState {
loading: boolean;
error: string | null;
data: string[];
}
interface Action {
type:string;
payload?: any;
}
const reducer = (state: RepositoriesState, action: Action): RepositoriesState => {
switch (action.type) {
case 'search_repositories':
return {
loading:true, error: null, data: []
}
case 'search_repositories_success':
return {
loading:false, error: null, data:action.payload
}
case 'search_repositories-error':
return {
loading: false, error: action.payload, data:[]
}
default:
return state;
}
};
export default reducer;
위의 코드에서 볼 포인트 들은 state interface, action interface, return type이 state interface 인 것들을 볼 수 있는데
Action 객체의 interface를 지정해주는 부분에서 조금 생소했다.
하지만 위의 리듀서를 보면 3개의 Action type 값을 가지고 있는데 더 확실하게 각 액션타입에 따른 타입을 지정하려면 이 각각에 대해서도 interface를 통해 타입을 지정해 줄 수 있다.
interface RepositoriesState {
loading: boolean;
error: string | null;
data: string[];
}
interface SearchRepositoriesAction{
type: 'search_repositories'
}
interface SearchRepositoriesSuccessAction{
type:'search_repositories_success',
payload:string[];
}
interface SearchRepositoriesErrorAction{
type: 'search_repositories_error',
payload:string;
}
const reducer = (
state: RepositoriesState,
action:
| SearchRepositoriesAction
| SearchRepositoriesSuccessAction
| SearchRepositoriesErrorAction
): RepositoriesState => {
switch (action.type) {
case 'search_repositories':
return {
loading:true, error: null, data: []
}
case 'search_repositories_success':
return {
loading:false, error: null, data:action.payload
}
case 'search_repositories_error':
return {
loading: false, error: action.payload, data:[]
}
default:
return state;
}
};
export default reducer;
이런식으로 각각 액션에 대해서도 따로 interface를 만들어서 문자열, 배열 등 확실하게 값에 타입을 매겨서 지정 할 수도 있다.
하지만 액션이 많으면 많을 수록 reducer 함수 부분에 action annotation이 난잡해지고 길어질 텐데 이를 type으로 한데 묶어 지정해줄 수 있고 action type 문자열들도 상수로 enum에 담아 나열 해 줄 수 있다.
최종적으로
interface RepositoriesState {
loading: boolean;
error: string | null;
data: string[];
}
type Action = | SearchRepositoriesAction
| SearchRepositoriesSuccessAction
| SearchRepositoriesErrorAction;
enum ActionTypes {
SEARCH_REPOSITORIES = 'search_repositories',
SEARCH_REPOSITORIES_SUCCESS = 'search_repositories_success',
SEARCH_REPOSITORIES_ERROR = 'search_repositories_error'
}
interface SearchRepositoriesAction{
type: ActionTypes.SEARCH_REPOSITORIES
}
interface SearchRepositoriesSuccessAction{
type:ActionTypes.SEARCH_REPOSITORIES_SUCCESS
payload:string[];
}
interface SearchRepositoriesErrorAction{
type: ActionTypes.SEARCH_REPOSITORIES_ERROR
payload:string;
}
const reducer = (
state: RepositoriesState,
action: Action
): RepositoriesState => {
switch (action.type) {
case ActionTypes.SEARCH_REPOSITORIES:
return {
loading:true, error: null, data: []
}
case ActionTypes.SEARCH_REPOSITORIES_SUCCESS:
return {
loading:false, error: null, data:action.payload
}
case ActionTypes.SEARCH_REPOSITORIES_ERROR:
return {
loading: false, error: action.payload, data:[]
}
default:
return state;
}
};
export default reducer;
마무리를 할 수 있으며 interface, action type enum 등 따로 폴더를 만들어서 export 해놓으면 다른 파일 들에서도 재사용이 가능하겠다.
'Reactjs' 카테고리의 다른 글
React recoil-persist 사용하기 (0) | 2022.11.24 |
---|---|
Tailwind 반응형 디자인 커스터 마이징의 필요성 (0) | 2022.11.04 |
React TypeScript 2가지 Component Type Annotation (0) | 2022.01.19 |
Redux-Saga 이해하기 (0) | 2022.01.11 |
redux-thunk 이해하기 (0) | 2022.01.11 |