그냥 쓰면 되지 않으려나...했는데 type의 벽에 가로막혀서
이거 어케 쓰냐... 하지말까...란 생각이 들었지만..
아무튼 극복함
이렇게 올리기 버튼을 누르면 숫자가 2 오르고 내리기 버튼을 누르면 숫자가 2 내려가는 버튼을 만들어보겠습니다.
npm install react-redux @reduxjs/toolkit
src/modules/CounterSlice.ts
import { createSlice } from '@reduxjs/toolkit';
const CounterSlice = createSlice({
name: 'CounterSlice',
initialState: { number: 0 },
reducers: {
up: (state, action) => {
state.number += action.payload;
},
down: (state, action) => {
state.number -= action.payload;
},
},
});
export const { up, down } = CounterSlice.actions;
export default CounterSlice.reducer;
대체로 비슷하게 작성합니다.
이렇게 작성해도 에러가 발생하지는 않습니다
하지만 좀 더 타입스크립트스럽게 코드를 바꿔보겠습니다.
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
interface CounterState {
number: number;
}
const initialState: CounterState = { number: 0 };
const CounterSlice = createSlice({
name: 'CounterSlice',
initialState,
reducers: {
up: (state, action: PayloadAction<number>) => {
state.number += action.payload;
},
down: (state, action: PayloadAction<number>) => {
state.number -= action.payload;
},
},
});
export const { up, down } = CounterSlice.actions;
export default CounterSlice.reducer;
PayloadAction
PayloadAction<number>구문은 up,down 리듀서에 전달된 작업이
number 유형의 payload 속성을 갖도록 지정해줍니다.
initialState에 interface를 활용해 타입을 지정해주고
action을 PayloadAction타입으로 갖도록 지정해줄 수 있습니다.
PayloadAction에 관련된 코드는
reduxjs/src/createAction.ts 파일에서 확인할 수 있습니다.
export type PayloadAction<
P = void,
T extends string = string,
M = never,
E = never
> = {
payload: P
type: T
} & ([M] extends [never]
? {}
: {
meta: M
}) &
([E] extends [never]
? {}
: {
error: E
})
이런식으로 구현이 되어있는데 저는 타입스크립트를 잘 몰라서
아는 분들이 해석해주시기 바랍니다. 알려줘잉
하여간 이렇게 작성하면 모가조음?
타입스크립트가 자동완성을 시켜줍니다.
타입스크립트 자동완성 최고 짱짱
src/modules/index.ts
이번엔 confiugreStore를 이용해 store를 생성해주겠습니다.
이 store를 생성하는 부분은 자동완성을 쓰지 않을것이어도
꼭 따라줘야합니다. 안하면 에러나니까요..
import TodoSlice from './TodoSlice';
import { configureStore } from '@reduxjs/toolkit';
import CounterSlice from './CounterSlice';
const store = configureStore({
reducer: {
counter: CounterSlice,
todoReducer: TodoSlice,
},
});
export default store;
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
configureStore를 이용해 작성하는 부분은 똑같이 하면 되는데
type을 export 해줘야합니다.
이 내보낸 타입값은 나중에 아주 유용하게 사용합니다.
src/app.tsx
import './App.css';
import React, { useState } from 'react';
import store from './modules';
import { Provider } from 'react-redux';
import Counter from './components/Counter';
function App() {
return (
<Provider store={store}>
<div>하이요</div>
<Counter />
</Provider>
);
}
export default App;
이 부분도 그냥 똑같이 작성해줍니다.
src/components/Counter.tsx
import React, { ReactNode } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { up, down } from '../modules/CounterSlice';
import { RootState } from '../modules/index'; // import your RootState type from your store file
interface Props {
number: number;
}
type PropsFromRedux = ConnectedProps<typeof connector>;
type ComponentProps = Props & PropsFromRedux;
const Counter = ({ number, up, down }: ComponentProps) => {
return (
<div>
<div>{number}</div>
<button
onClick={() => {
up(2);
}}
>
올리기
</button>
<button
onClick={() => {
down(2);
}}
>
내리기
</button>
</div>
);
};
const mapStateToProps = (state: RootState) => ({
number: state.counter.number,
});
const mapDispatchToProps = { up, down };
const connector = connect(mapStateToProps, mapDispatchToProps);
export default connector(Counter);
연동하는 부분에서 큰 차이가 있습니다.
전 connect 함수를 이용할것인데 그런 경우 다음과 같이 구현하게됩니다.
왜 저런코드가 나오는지는 나중에 공부할게요... 일단은 쓰겠읍니다.
'typescript' 카테고리의 다른 글
Typescript의 컴파일 과정과 성능 (0) | 2023.04.27 |
---|---|
TypeScript interface cheat sheet (0) | 2023.04.19 |
ts.config.json 설정 알아보기 (0) | 2023.04.18 |
제네릭 (0) | 2023.04.17 |
리터럴 타입 니가 몬데.. (0) | 2023.04.17 |