[React] Redux toolkit slice

유아현·2023년 3월 9일
0

React

목록 보기
26/28
post-thumbnail

✨ Intro

관련된 상태끼리 다루기 위해서 여러 slice를 다루는 방법을 알아보자. 모든 slice는 각 slice를 구분하기 위해 name이 필요하다.


📌 Slice 생성

  • slice를 생성해 주기 위해서 아래와 같은 형식을 가진다.
  createSlice({
    name: 'slice name', 
    initialState: 초기값,
    reducers: {}
  })

초기값으로는 다음과 같이 지정해 줄 수도 있고

  createSlice({
    name: 'slice name', 
    initialState: { isAuthenticated: false },
    reducers: {}
  })

따로 객체를 선언한 변수로 할당해도 된다.

const initialAuthState = {
  isAuthenticated: false,
};

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    },
  },
});

src/store/index.js

import { createSlice, configureStore } from '@reduxjs/toolkit';

/*
! 모든 slice는 name이 있어야 한다.
=> 상태마다 식별자가 필요하다는 것
  payload가 있는 경우에는 어떻게 할까? 기본적으로 payload를 dispatch를 통해서
  전달하게 되면 payload가 default 키값으로 들어가기 때문에 action.payload로 접근해야 한다.
*/

// !관련된 상태끼리 다루기

//? Counter와 관련된 State
const initialCounterState = { counter: 0, showCounter: true };

const counterSlice = createSlice({
  name: 'counter',
  initialState: initialCounterState,
  reducers: {
    increase(state) {
      state.counter = state.counter + 1;
    },
    increaseByInput(state, action) {
      state.counter = state.counter + action.payload;
    },
    decrease(state) {
      state.counter = state.counter - 1;
    },
    toggle(state) {
      state.showCounter = !state.showCounter;
    },
  },
});


//? Counter와 관련된 State
const initialAuthState = {
  isAuthenticated: false,
};

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    },
  },
});

/*
  하나의 Application에는 하나의 store만 존재하기 때문에 configureStore도 한 번만 호출해야 한다.
  configureStore의 reducer은 리듀서 함수를 인자로 받을 뿐만 아니라
  리듀서 맵을 역할을 하는 객체로서 받기도 한다.

  아래와 같은 counter, auth 등 각 개별의 리듀서들은
  나중에 하나의 주요 리듀서로 자동으로 합쳐진다.
  그리고 주요 리듀서를 스토어에 노출한다.
  이런 식으로 여러 개의 slice와 리듀서를 합칠 수 있는 것이다.
*/
const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
    auth: authSlice.reducer,
  },
});

//! 액션 생성자
export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;
export default store;

📌 dispatch를 이용해, action 요청하기

버튼 클릭 시, 로그인 하는 로직

src/components/Auth.js

import classes from './Auth.module.css';
import { useDispatch } from 'react-redux';
import { authActions } from '../store';

const Auth = () => {
  const dispatch = useDispatch();

  const loginHandler = (event) => {
    event.preventDefault();
    dispatch(authActions.login());
  };
  return (
    <main className={classes.auth}>
      <section>
        <form onSubmit={loginHandler}>
          <div className={classes.control}>
            <label htmlFor="email">Email</label>
            <input type="email" id="email" />
          </div>
          <div className={classes.control}>
            <label htmlFor="password">Password</label>
            <input type="password" id="password" />
          </div>
          <button>Login</button>
        </form>
      </section>
    </main>
  );
};

export default Auth;

📌 useSelector를 이용해 store에 접근하기

로그인 상태가 true인 경우, nav 보이게 하기

src/components/Header.js

import { useSelector, useDispatch } from 'react-redux';
import classes from './Header.module.css';
import { authActions } from '../store';

const Header = () => {
  const dispatch = useDispatch();
  const isAuth = useSelector((state) => state.auth.isAuthenticated);

  const logoutHandler = (event) => {
    event.preventDefault();
    dispatch(authActions.logout());
  };

  return (
    <header className={classes.header}>
      <h1>Redux Auth</h1>
      {isAuth && (
        <nav>
          <ul>
            <li>
              <a href="/">My Products</a>
            </li>
            <li>
              <a href="/">My Sales</a>
            </li>
            <li>
              <button onClick={logoutHandler}>Logout</button>
            </li>
          </ul>
        </nav>
      )}
    </header>
  );
};

export default Header;

0개의 댓글