import { createStore } from "redux";
const initialState = { counter: 0, showCounter: true };
const counterReducer = (state = initialState, action) => {
if (action.type === "increment") {
return { counter: state.counter + 1, showCounter: state.showCounter };
}
if (action.type === "increase") {
return {
counter: state.counter + action.value,
showCounter: state.showCounter,
};
}
if (action.type === "decrement") {
return { counter: state.counter - 1, showCounter: state.showCounter };
}
if (action.type === "toggle") {
return { counter: state.counter, showCounter: !state.showCounter };
}
return state;
};
const store = createStore(counterReducer);
export default store;
===
식으로 식별자를 찾아가면 리튜서는 단 하나의 오차도 허용하지 않는다.import { createSlice, createReducer } from "@reduxjs/toolkit";
createSlice
는 한번에 여러가지를 simplify하기 때문에 createSlice
를 사용하도록 하자import { createSlice, configureStore } from "@reduxjs/toolkit";
const initialCounterState = { counter: 0, showCounter: true };
const counterSlice = createSlice({
name: "counter",
initialState: initialCounterState,
reducers: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
increase(state, action) {
state.counter = state.counter + action.payload;
},
toggleCounter(state) {
state.showCounter = !state.showCounter;
},
},
});
const initialAuthState = { isAuthenticated: false };
const authSlice = createSlice({
name: "authentication",
initialState: initialAuthState,
reducers: {
login(state) {
state.isAuthenticated = true;
},
logout(state) {
state.isAuthenticated = false;
},
},
});
const store = configureStore({
reducer: { counter: counterSlice.reducer, auth: authSlice.reducer },
});
export const counterActions = counterSlice.actions;
export const authActions = authSlice.actions;
export default store;
위 코드를 보면 앞서 포스팅 했던 것 과 반대로 절대 하지말라는 기존의 state에 접근하여 변경하는 행동을 하고있는데 이는 Redux toolkit과 createSlice와 같은 함수를 사용하면 괜찮다.
그리고 사실 RTK가 이 코드를 캡처하고 다른 third party library인 imer
를 사용하여 사용자로 하여금 state에서 직접적으로 변경하는 것 처럼 편리하게 해준다.
하지만 앞서 언급했듯 실제로 기존 state 개체를 조작하는 대신, 새 state 개체를 생성하여 일부 변경 불가능한 코드로 변환되도록 한다.
왜냐하면 Redux toolkit는 내부적으로 immer라는 다른 패키지를 사용하는데 위와같은 코드를 감지하고 자동으로 원래 있는 state를 복제한 후 새로운 state 객체를 생성하고 모든 state를 변경할 수 없게 유지하고, 우리가 변경한 state는 변하지 않도록 오버라이드한다.
하지만 slice의 state가 많아지면 또 문제가 생길 수 있다. 왜냐면 createStore에는 하나의 reducer만 전달해야하는데 slice state가 여러개라면 state별로 reducer가 여러개가 될 수 밖에 없기 매문이다.
그래서 있는 것이 바로 combineReducer이다.
import { createStore, combineReducers } from "redux";
구문이 있긴 하지만 RTK를 이용하여 configureStore에 대하여 알아보자const store = createStore(counterSlice.reducer);
이게
const store = configureStore({
reducer:counterSlice.reducer
});
요러게 바뀌는데 이때 configureStore는 property로 반드시 reducer라는 단수 특징을 갖는다.
당연하게도 Store는 앞서 포스팅 했듯 전역 state를 담당하는 하나의 리듀서 함수만 있어야하기 때문이다.
그래서 지금은 1개의 state slice를 갖기 때문에 저렇게 써놔도 무방하지만 만약 여러개의 state slice를 갖는다면
const store = configureStore({
reducer: {키값 : 슬라이스, 키값2 : 슬라이스2 ...}
});
export const counterActions = counterSlice.actions;
counterSlice.actions.toggleCounter()
은 action 객체를 반환하는데 이게{type:"자동으로 반들어지는 unique한 id값"}
이 반환된다. import { useDispatch, useSelector } from "react-redux";
import { authActions } from "../store/reduxLogix";
import classes from "./Header.module.css";
const Header = () => {
const dispatch = useDispatch();
const isAuth = useSelector((state) => state.auth.isAuthenticated);
const logoutHandler = () => {
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;
{type:자동생성된id값, payload:매개변수값}
이런식으로 담겨서 RTK의 store로 넘어간다.
따라서! store에 있는 action.값 => action.payload로 바꾸어주어야만 한다!
또한 보면 그동안 작업해온 react는 실행하는 것이 아닌 pointing 만 하였는데 이렇게 실행을 해주는 이유는
실제로 실행해야 하는 action creator 메서드이기 때문에 여기에서는 메서드로 실행해야 한다.
그리고 그것들을 실행하면 action 객체를 반환한다. => action creator 자세히
이때 action export까지 함께 가지고 가야한다.
import { createSlice } from "@reduxjs/toolkit";
const initialCounterState = { counter: 0, showCounter: true };
const counterSlice = createSlice({
name: "counter",
initialState: initialCounterState,
reducers: {
increment(state) {
state.counter++;
},
decrement(state) {
state.counter--;
},
increase(state, action) {
state.counter = state.counter + action.payload;
},
toggleCounter(state) {
state.showCounter = !state.showCounter;
},
},
});
export const counterActions = counterSlice.actions;
export default counterSlice.reducer;
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from "./counter";
import authReducer from "./auth";
const store = configureStore({
reducer: { counter: counterReducer, auth: authReducer },
});
export default store;