Redux Toolkit을 사용한 전역 상태 관리
개발

Redux Toolkit을 사용한 전역 상태 관리

작성일: 2023년 08월 18일

1. Redux ToolKit

Redux는 React.js 애플리케이션에서 사용되는 상태 관리 라이브러리로 store를 통해 전역의 state를 관리하고 저장한다. 여기서 더 확장된 RTK는 리덕스(Redux) 상태관리 라이브러리를 사용하기 쉽고 효율적으로 코드를 작성할 수 있도록 돕는 패키지이다.

1) redux와 RTK의 차이

분류 | Redux | RTK

:-::::

코드량 | 많은 코드 양 | 적은 코드 양

Immutable 추가 | Immutable 업데이트 미지원 | Immutable 업데이트 지원

createSlice 함수 추가| 상태, 액션, 리듀서를 각각 개별적으로 작성 | createSlice 함수로 상태, 액션, 리듀서를 한 번에 생성

configureStore 함수 추가 | 스토어 생성 코드를 따로 작성 | configureStore 함수로 스토어 생성 코드 자동 생성

기본적인 미들웨어 포함 | 기본 미들웨어 미포함 | 몇 가지 기본 미들웨어 포함


2) 메서드 정리

메서드 설명 |

:-:-

configureStore() | Redux Store를 구성하는 메서드로, reducer 및 middleware를 설정하고 store를 반환

createReducer() | 일반적인 reducer 함수를 작성하는 데 사용

createAction() | 일반적인 액션 생성 함수를 작성하는 데 사용

createSlice() |Redux Toolkit에서 reducer를 작성하는 유틸리티 메서드로 초기 상태 및 reducer 함수를 정의하고, 액션 생성 함수 생성.

createAsyncThunk() | 비동기 작업을 수행하는 Action Creator를 생성

createEntityAdapter() | 비정규화된 엔티티 데이터를 쉽게 관리

createSelector() | Reselect 라이브러리와 함께 사용하여 성능 최적화된 셀렉터를 생성

useSelector() | Redux store에서 state를 불러오는 메서드

useDispatch() | Redux store에서 action을 dispatch하는 Hook으로 컴포넌트에서 Redux store의 state를 변경

2. Store & Slice 구성 및 Provider 설정

state의 초기값을 설정하고 state에 맞는 action을 세팅한다.

//userSlice.ts
import {createSlice} from '@reduxjs/toolkit';

const initialState = {
  nickName: '',
  email: '',
  userId: '',
  accessToken: '',
};

export const userSlice = createSlice({
  name: 'user',
  initialState,
  reducers: {
    // 모든 사용자 정보 저장
    setUser(state, action) {
      state.nickName = action.payload.name;
      state.email = action.payload.email;
      state.userId = action.payload.userId;
    },
    setNickName(state, action) {
      state.nickName = action.payload;
    },
    setEmail(state, action) {
      state.email = action.payload;
    },
    setUserId(state, action) {
      state.userId = action.payload;
    },
    setAccessToken(state, action) {
      state.accessToken = action.payload;
    },
  },
});

export const {setUser, setNickName, setEmail, setUserId, setAccessToken} = userSlice.actions;
export default userSlice;

애플리케이션 상태를 담고 있는 객체인 Store를 구성한다.

//store.ts
import {configureStore} from '@reduxjs/toolkit';
import userSlice from './userSlice';

const store = configureStore({
  reducer: {
    user: userSlice.reducer,
  },
});

export default store;

App 페이지 최상위에 Provider로 스토어를 등록한다.

//최상위 app.tsx
import {View, StyleSheet} from 'react-native';
import {NavigationContainer, DefaultTheme} from '@react-navigation/native';
import {AuthStack} from './src/navigations/StackNavigator';
import {Provider} from 'react-redux';
import store from './src/util/redux/store';

const App = () => {
  return (
    <Provider store={store}>
      <NavigationContainer
        theme={{
          ...DefaultTheme,
          colors: {
            ...DefaultTheme.colors,
            background: 'white',
          },
        }}
        independent={true}>
        <View style={styles.container}>
          <AuthStack />
        </View>
      </NavigationContainer>
    </Provider>
  );
};

export default App;

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#ffffff',
  },
});

3. Redux Toolkit으로 state 관리하기

이전 splash와 login screen에서 AsyncStrage에 토큰 정보를 저장했는데 로그인 시 사용될 userId와 nickname, email, Authorization bearer token에 전달할 accessToken을 전역 state에 저장하여 유저 정보가 포함된 모든 요청에 가져와서 사용한다.

// login.tsx
//...중략
import {useDispatch} from 'react-redux';
import {setUserId, setAccessToken} from '../../util/redux/userSlice';

const dispatch = useDispatch();
const loginAuth = async () => {
    if (url !== undefined) {
      try {
        const response = await axios.post(`${url}api/v1/users/login`, data);
        const {accessToken, refreshToken, userId} = response.data;
        // 자동 로그인 정보 수집
        if (autoLogin) {
          await storageSetValue('tokens', {accessToken, refreshToken});
        } else await storageDeleteValue('tokens');
        // store에 userId와 토큰 저장
        dispatch(setUserId(userId)); // userId 저장
        dispatch(setAccessToken(accessToken)); // 엑세스토큰 저장
        //메인화면으로 이동
        navigation.navigate('MainTab');
      } catch (error: any) {
        navigation.reset({routes: [{name: 'Login'}]});
      }
    }
  };

//component.tsx
import {useSelector} from 'react-redux';

  const user = useSelector((state: any) => state.user);
  console.log(user);
/* {
  accessToken: 'your accessToken',
  email: '',
  nickName: '',
  userId: 1,
}; */