EXPO) React Native에 TypeScript+Redux ToolKit 적용#1
안녕하세요. 후르륵짭짭입니다.
취미 생활로 하는 Expo에 Redux ToolKit을 적용한 내용을 작성하도록 하겠습니다.
https://redux-toolkit.js.org/usage/usage-with-typescript
Usage With TypeScript | Redux Toolkit
redux-toolkit.js.org
이 글을 보고 Redux ToolKit을 Typescript로 적용하는 방법을 공부를 해보려고 합니다.
** 설치 **
npm install @reduxjs/toolkit react-redux redux-thunk
** CreateSlice **
실질적으로 행동을 담당하는 역할을 한다.
createSlice는 Redux Toolkit에서 리듀서와 관련된 로직을 간단하게 작성할 수 있도록 도와주는 함수다.
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { fetchInfos } from "./thunks";
interface ContentsStateType { // 슬라이스 초기 상태 타입
count: number
}
const initialState: ContentsStateType = {
count: 0
};
const counterReducer = createSlice({
name: 'counter',
initialState: initialState,
reducers: {
addCount(state,actions: PayloadAction<number>) {
console.log(actions.payload)
state.count + actions.payload
}
},
extraReducers: (builder) => {
builder.addCase(fetchInfos.fulfilled, (state, { payload }) => {
console.log("success extra Reducer",payload)
state.count + 10
}),
builder.addCase(fetchInfos.rejected, (state, { payload }) => {
console.log("reject extra Reducer",payload)
state.count = state.count - 10
})
}
})
export const { addCount } = counterReducer.actions
export default counterReducer
- Reducer -
Reducer에는 State와 Action이 존재한다.
State는 값이 변경이 되면 Provider 하위의 View를 rendering 시켜준다.
Action에는 Payload라는 것이 존재하는데, 이것은 Input 값이라 생각하면 된다.
- ExtraReducer -
//HTTP.tsx
import axios from "axios";
let baseUrl: string = "https://testproject2-2e6ef-default-rtdb.firebaseio.com/"
export interface GetInfoResponse {
userName: string
}
export const getInfos = async (): Promise<GetInfoResponse> => {
let response = await axios.get<GetInfoResponse>(baseUrl + "infos.json")
return response.data
}
//thunks.tsx
import { createAsyncThunk } from "@reduxjs/toolkit"
import { GetInfoResponse } from "../utilitys/http"
import { RootState } from "./store"
import { getInfos } from "../utilitys/http"
export const fetchInfos = createAsyncThunk<GetInfoResponse,void,{ state: RootState, rejectValue: { error: string } }>(
'counter/getInfos',
async (_, { getState , rejectWithValue }) => {
const state = getState().counter
console.log("state in FetchInfos", state)
if (state.count % 2 !== 0 ) {
console.log("state Count is Not 2")
return rejectWithValue({error: "Fail"})
}
const response = await getInfos()
return response
}
)
CreateAsyncThunk라는 것이 존재한다.
이것은 비동기 작업에 대한 Reducer를 만들 때 사용한다.
CreateAsyncThunk<Response Type, Input Type, 각종 옵션>( 이름 , 비동기함수)
이렇게 작성해줘야한다.
각종 옵션은 여러가지가 있는데, state의 타입과 에러일 경우에 반환하는 rejectValue 타입을 주도록 만들었다.
extraReducers: (builder) => {
builder.addCase(fetchInfos.fulfilled, (state, { payload }) => {
console.log("success extra Reducer",payload)
state.count + 10
}),
builder.addCase(fetchInfos.rejected, (state, { payload }) => {
console.log("reject extra Reducer",payload)
state.count = state.count - 10
})
}
그리고 이렇게 extraReducer에서 state에 대한 옵션을 처리하고 있다.
fulfilled는 성공했을 때, reject는 실패 했을 때, 다음 함수를 타게 된다.
이때, payload에는 반환되는 Input이 들어온다.
** Store **
이렇게 행동에 대한 함수들을 만들었으니, 행동을 사용할 수 있도록 만들어줘야한다.
import { configureStore, combineReducers } from "@reduxjs/toolkit"
import counterReducer from "./counterReducer"
import { useSelector, useDispatch , TypedUseSelectorHook} from 'react-redux';
const rootReducer = combineReducers({
counter: counterReducer.reducer
// Add more slices as needed
});
const store = configureStore({
reducer: rootReducer
})
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export default store
이렇게 만들었던 reducer를 combineReducers에 넣어준다.
여러가지 Reducer를 넣을 수 있다.
그리고 configureStore를 통해서 reducer를 넣어준다.
https://velog.io/@jjh099/Redux-configureStore-createSlice-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
[Redux] configureStore , createSlice 사용하기
configureStore는 Redux 스토어를 생성하는 함수로, Redux의 기본 createStore 함수보다 간편하게 스토어를 설정할 수 있도록 도와준다.
velog.io
자세한 내용은 여기에 있다.
- 사용하기 -
import { useSelector, useDispatch , TypedUseSelectorHook} from 'react-redux';
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
외부에서 TypeScript형식으로 사용하기 위해서는
Dispatch와 Selector를 타입을 지정하여 새롭게 정의 해줘야한다.
** 실제 앱 적용 **
import { Provider } from 'react-redux';
import store from './store/store';
import CounterScreen from './CounterScreen';
export default function App() {
return (
<Provider store={store}>
<View style={styles.container}>
<CounterScreen />
<StatusBar style="auto" />
</View>
</Provider>
);
}
이렇게 내가 사용하려고 하는 View에
<Provider> 컴포넌트로 감싸준다. 이때, State를 감지할 Store를 넣어준다.
import { addCount } from './store/counterReducer';
import { RootState } from './store/store';
import { useAppSelector, useAppDispatch } from './store/store';
import { fetchInfos } from './store/thunks';
export default function CounterScreen() {
const counterState = useAppSelector( (state: RootState) => state.counter)
const dispatch = useAppDispatch()
const countUp = (_: any) => {
dispatch(addCount(1))
}
const getInfo = (_: any) => {
dispatch(fetchInfos())
}
return (
<View style={styles.info}>
<Text>Count Of App : {counterState.count}</Text>
<Pressable onPress={countUp}>
<Text>Count Up</Text>
</Pressable>
<Pressable onPress={getInfo}>
<Text>getInfo</Text>
</Pressable>
</View>
);
}
그리고 이렇게 useAppSelector로 State를 가져올 수 있고
dispatch를 통해서 함수 호출을 해줄 수 있다.
참고사이트:
- basic
https://medium.com/@Has_San/difference-between-redux-and-redux-toolkit-7e1e5431546d
Difference Between Redux and Redux Toolkit
In the realm of state management for React applications, Redux has become a powerful and widely adopted tool. Redux offers a predictable…
medium.com
https://dev.to/emmyjaff/creating-a-react-native-expo-project-with-redux-toolkit-and-thunk-73k
Creating a React Native Expo project with Redux Toolkit and Thunk
In this guide, I will walk you through the process step by step. Please make sure you have Node.js,...
dev.to
- AsyncThunk
https://velog.io/@raejoonee/createAsyncThunk
Redux Toolkit의 createAsyncThunk로 비동기 처리하기
Redux Toolkit에는 내부적으로 thunk를 내장하고 있어서, 다른 미들웨어를 사용하지 않고도 비동기 처리를 할 수 있다.
velog.io
- 고급 TypeScript + Redux
https://velog.io/@velopert/use-typescript-and-redux-like-a-pro
TypeScript 환경에서 Redux를 프로처럼 사용하기
이번에 준비한 튜토리얼에서는 TypeScript 환경에서 Redux를 프로처럼 사용하는 방법을 다뤄보도록 하겠습니다. 왜 제목이 "프로처럼"이냐! 사실은 조금 주관적입니다. 이 튜토리얼에서는 지금까지
velog.io
- Action Type지정
https://stackoverflow.com/questions/69834242/redux-toolkit-typescript-what-is-my-payloadaction-type
Redux toolkit typescript -- what is my PayloadAction type?
I'm trying to write a slice for RTK and I'm not sure what the type of my payload should be. My state -- InviteeState is an array of people objects interface InviteeState { people: { name: str...
stackoverflow.com
https://velog.io/@ajm0718/Vite-TS-React%EC%97%90-Redux-Toolkit-%EC%A0%81%EC%9A%A9%ED%95%98%EA%B8%B0
React + TS에서 Redux Toolkit 적용하기
이전에 Redux에 대해서 기본 개념을 익혔으니 이제 프로젝트에 적용하기 위해 Redux Toolkit에서 사용하는 용어를 먼저 알아보자.
velog.io
https://velog.io/@jjh099/Redux-configureStore-createSlice-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0
[Redux] configureStore , createSlice 사용하기
configureStore는 Redux 스토어를 생성하는 함수로, Redux의 기본 createStore 함수보다 간편하게 스토어를 설정할 수 있도록 도와준다.
velog.io
- TypeScript 기본
https://velog.io/@jinyoung985/TypeScript-%EA%B8%B0%EB%B3%B8-%EB%AC%B8%EB%B2%95-%EC%A0%95%EB%A6%AC
[TypeScript] 타입스크립트 기본 문법 정리
개발 공부를 시작하고 지금까지 자바스크립트를 공부하고, 또 자바스크립트로 다양한 프로젝트를 진행해왔다.하지만 타입스크립트라는 언어를 알게 된 후부터 자바스크립트의 단점이 내게 부
velog.io