redux는
1. state를 한곳에 관리할 수 있어서 compoent들이 props없이 state를 다루기 쉽고
2. 수정방법을 미리 reducer라는 함수로 정의해놔서 state 수정 시 발생하는 버그를 줄일 수 있음
redux 설치 : npm install redux react-redux
redux는 type정의가 미리 잘 되어있어 그냥 설치만 하면 됨.
일단 예제로 <button>을 누르면 state가 +1, -1되는 예제를 작성해보겠음
그러려면
1. state가 필요하고,
2. +와 -하는 방법을 정의해둔 reducer가 필요할 듯
파일을 여러개로 나누면 이해가 어려우니 보기쉽게 index.ts에 필요한 모든 코드를 적어보겠음.
(index.ts)
import { Provider } from 'react-redux';
import { createStore } from 'redux';
interface Counter {
count : number
}
const 초기값 :Counter = { count: 0 };
function reducer(state = 초기값, action :any) {
if (action.type === '증가') {
return { count : state.count + 1 }
} else if (action.type === '감소'){
return { count : state.count - 1 }
} else {
return initialState
}
}
const store = createStore(reducer);
// store의 타입 미리 export 해두기
export type RootState = ReturnType<typeof store.getState>
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
지금 보이는 변수와 함수에 타입지정을 하면 됨
그래서 redux쓸 때는 똑같이 state초기값과 reducer함수의 타입지정을 잘하면 됨.
state는 사실 타입지정이 필요 없음
초기값넣으면 타입지정이 잘 됨
action은 나중에 dispatch날릴 때 집어넣는 object자료와 똑같이 생겨야 함
그래서 그거 그대로 타입지정을 해주면 되는데 대부분 {type:string, payload:number}이런식으로 생겼음.
위에선 any라고 대충 넣음
어떤 걸 return 해줘야 할지 적어두면 됨
딱 봐도 초기값이랑 유사하게 생기면 될 듯
그리고 reducer 타입지정은 전부 reducer 안의 코드들을 잘못 써서 생기는 버그를 약간 방지하는 요오임.
App.tsx같은데서 dispatch()를 잘 쓰냐 못 쓰냐 캐치해 주지는 않음
redux에 있던 state를 가져오려면
mapStateToProps도 있지만 useSelector훅을 쓰면 간단하게 가져올 수 있음
그리고 state를 변경하려면 useDispatch훅을 쓰면 dispatch를 간단하게 날릴 수 있음
import React from 'react';
import { useDispatch, useSelector } from 'react-redux'
import { Dispatch } from 'redux'
import {RootState} from './index'
function App() {
const 꺼내온거 = useSelector( (state :RootState) => state );
const dispatch :Dispatch = useDispatch();
return (
<div className="App">
{ 꺼내온거.count }
<button onClick={()=>{dispatch({type : '증가'})}}>버튼</button>
<Profile name="kim"></Profile>
</div>
);
}
타입지정은 그냥
state가 어떻게 생겼는지 파악한 다음 타입을 알아서 손수 지정해주거나
귀찮으면 index.ts안에 타입을 exprot해서 가져와도 됨
index.ts안에 있던 exprot type RootState = ReturnType<typeof store.getState>
← 이 코드가 store의 타입을 미리 export해두는 방법임
import { Dispatch } from 'redux'
이렇게 타입을 가져와서
const dispatch : Dispatch
이렇게 쓰면 됨
그럼 dispatch날릴 때 안에 파라미터 안쓰면 에러내줌
신식 redux를 사용하고 싶으면 redux, react-redux에 이어
npm install @reduxjs/toolkit
@reduxjs/toolkit 라이브러리를 추가로 설치해주면 됨.
그럼 이제 조금 더 깔끔하게 코드를 짤 수 있음.
위와 같은 예제로 <button>버튼을 누르면 state가 +1, -1되는 예제를 만들어보겠음
index.ts에 필요한 모든 코드를 적었음
(index.ts)
import { createSlice, configureStore } from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
const 초기값 = { count: 0, user : 'kim' };
const counterSlice = createSlice({
name: 'counter',
initialState : 초기값,
reducers: {
increment (state){
state.count += 1
},
decrement (state){
state.count -= 1
},
incrementByAmount (state, action :any){
state.count += action.payload
}
}
})
let store = configureStore({
reducer: {
counter1 : counterSlice.reducer
}
})
//state 타입을 export 해두는건데 나중에 쓸 데가 있음
export type RootState = ReturnType<typeof store.getState>
//수정방법 만든거 export
export let {increment, decrement, incrementByAmount} = counterSlice.actions
그리고 하단에 <Provider store = { store }>
이런 코드를 추가해주면 끄읏-
타입지정은
action 타입지정은 방법이 따로 있는데
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
(상단 생략)
incrementByAmount (state, action: PayloadAction<number>){
state.value += action.payload
},
위처럼 타입지정을 하라고 권장함
나중에 dispatch할 때 보내는 데이터가 있으면 그걸 payload라고 부르는데,
그 자료의 타입을 <>안에 집어넣어서 타입지정하라는 소리임
문자를 payload로 보낼거면 string을 집어넣고~ 이런식임
import { useDispatch, useSelector } from 'react-redux'
import {RootState, increment} from './index'
function App() {
const 꺼내온거 = useSelector( (state :RootState) => state);
const dispatch = useDispatch();
return (
<div className="App">
{꺼내온거.counter1.count}
<button onClick={()=>{dispatch(increment())}}>버튼</button>
</div>
);
}
타입지정은 state와 dispatch안에 해주면 됨
공식문서에서는
index.ts에서 export type AppDispatch = typeof store.dispatch
해두고
App.tsx에서 import해와서 useDispatch<AppDispatch>()
이렇게 타입지정하라고 되어있긴 함
귀찮으면 예전 방식으로 사용해도 무관