본문 바로가기
React/Native

EXPO) React Native에 TypeScript+Redux ToolKit 적용#1

by 후르륵짭짭 2024. 12. 8.
728x90
반응형

안녕하세요. 후르륵짭짭입니다.

취미 생활로 하는 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

 

 

728x90
반응형

댓글