관련된 상태끼리 다루기 위해서 여러 slice를 다루는 방법을 알아보자. 모든 slice는 각 slice를 구분하기 위해 name이 필요하다.
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;
},
},
});
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;
버튼 클릭 시, 로그인 하는 로직
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;
로그인 상태가 true인 경우, nav 보이게 하기
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;