在第 15 天的文章中我们做了一个范例,现在我们要用 Redux Toolkit 去改写它。
我们将原本范例的 store 和 reducer 做改写。
调整前:
// store/index.js
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.amount,
showCounter: state.showCounter
};
}
if (action.type === "decrement") {
return {
counter: state.counter - 1,
showCounter: state.showCounter
};
}
if (action.type === "toggle") {
return {
showCounter: !state.showCounter,
counter: state.counter
};
}
return state;
};
const store = createStore(counterReducer);
export default store;
调整後:
// store/index.js
import { createSlice, configureStore } from "@reduxjs/toolkit";
const initialState = { counter: 0, showCounter: true };
const counterSlice = createSlice({
name: "counter",
initialState,
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 store = configureStore({
reducer: counterSlice.reducer
});
export const counterActions = counterSlice.actions;
export default store;
将 Counter 元件做调整
调整前:
// Counter.js
import { useSelector, useDispatch } from "react-redux";
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const incrementHandler = () => {
dispatch({ type: "increment" });
};
const increaseHandler = () => {
dispatch({ type: "increase", amount: 10 });
};
const decrementHandler = () => {
dispatch({ type: "decrement" });
};
const toggleCounterHandler = () => {
dispatch({ type: "toggle" });
};
return (
<>
{show && <div>{counter}</div>}
<button onClick={incrementHandler}>Increment</button>
<button onClick={increaseHandler}>Increase by 10</button>
<button onClick={decrementHandler}>Decrement</button>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</>
);
};
export default Counter;
调整後:
// Counter.js
import { useSelector, useDispatch } from "react-redux";
import { counterActions } from "./store/index";
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const incrementHandler = () => {
dispatch(counterActions.increment());
};
const increaseHandler = () => {
dispatch(counterActions.increase(10)); // { type: SOME_UNIQUE_IDENTIFIER, payload: 10 }
};
const decrementHandler = () => {
dispatch(counterActions.decrement());
};
const toggleCounterHandler = () => {
dispatch(counterActions.toggleCounter());
};
return (
<>
{show && <div>{counter}</div>}
<button onClick={incrementHandler}>Increment</button>
<button onClick={increaseHandler}>Increase by 10</button>
<button onClick={decrementHandler}>Decrement</button>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</>
);
};
export default Counter;
完成以上两个步骤後就可以正常运作计数的程序了,当前范例如下:
范例程序
不过我们再多加一点东西进去,了解如何去管理多个 createSlice。
除了原本的档案外,有再增加一些空白的档案(Auth.js/auth.js/index.js),调整档案後的结构如下:
|-- src
|-- App.js
|-- index.js
|-- components
| |-- Counter.js
| |-- Auth.js
|-- store
|-- counter.js
|-- auth.js
|-- index.js
调整 App.js。
import { useSelector, useDispatch } from 'react-redux';
import Counter from './components/Counter';
import Auth from './components/Auth';
import { authActions } from './store/auth';
function App() {
const dispatch = useDispatch();
const isAuth = useSelector(state => state.auth.isAuthenticated);
const logoutHandler = () => {
dispatch(authActions.logout());
};
return (
<>
{!isAuth && <Auth />}
{isAuth && <button onClick={logoutHandler}>Logout</button>}
<Counter />
</>
);
}
export default App;
counter.js 的部分,做一些微调,注解起来的是旧的程序码,我们要把 store 移到 store/index.js 里去建立。
// import { createSlice, configureStore } from "@reduxjs/toolkit";
import { createSlice } from '@reduxjs/toolkit';
const initialState = { counter: 0, showCounter: true };
const counterSlice = createSlice({
name: "counter",
// initialState,
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 store = configureStore({
// reducer: counterSlice.reducer
// });
export const counterActions = counterSlice.actions;
export default store;
接着也完成 auth.js。
import { createSlice } from '@reduxjs/toolkit';
const initialAuthState = {
isAuthenticated: false,
};
const authSlice = createSlice({
name: 'authentication',
initialState: initialAuthState,
reducers: {
login(state) {
state.isAuthenticated = true;
},
logout(state) {
state.isAuthenticated = false;
},
},
});
export const authActions = authSlice.actions;
export default authSlice.reducer;
在 store/index.js 里面建立 store,并将多个 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;
Counter 元件只需修改引入 actions 的档案。
import { useSelector, useDispatch } from "react-redux";
// import { counterActions } from "./store/index";
import { counterActions } from '../store/counter';
const Counter = () => {
const dispatch = useDispatch();
const counter = useSelector((state) => state.counter);
const show = useSelector((state) => state.showCounter);
const incrementHandler = () => {
dispatch(counterActions.increment());
};
const increaseHandler = () => {
dispatch(counterActions.increase(10)); // { type: SOME_UNIQUE_IDENTIFIER, payload: 10 }
};
const decrementHandler = () => {
dispatch(counterActions.decrement());
};
const toggleCounterHandler = () => {
dispatch(counterActions.toggleCounter());
};
return (
<>
{show && <div>{counter}</div>}
<button onClick={incrementHandler}>Increment</button>
<button onClick={increaseHandler}>Increase by 10</button>
<button onClick={decrementHandler}>Decrement</button>
<button onClick={toggleCounterHandler}>Toggle Counter</button>
</>
);
};
export default Counter;
完成 Auth 元件後,就完成这次的实作。
import { useDispatch } from "react-redux";
import { authActions } from "../store/auth";
const Auth = () => {
const dispatch = useDispatch();
const loginHandler = (event) => {
event.preventDefault();
dispatch(authActions.login());
};
return (
<form onSubmit={loginHandler}>
<div>
<label htmlFor="email">Email</label>
<input type="email" id="email" />
</div>
<div>
<label htmlFor="password">Password</label>
<input type="password" id="password" />
</div>
<button>Login</button>
</form>
);
};
export default Auth;
本次的实作范例在以下连结,明天将进入下一个单元:
<<: day 23 - 取号机 AUTO_INCREMENT(MYSQL) > INCR(Redis) > snowflake演算法
>>: Day 19: Security Hub 单一帐号/启用Org.後的布建
门口招牌标榜「来自梧栖」,因为广义来说,天圆也算是「新天地」的旗下品牌。 新天地是台中老字号的品牌,...
上回介绍闭包概念以及闭包大致运用,这次则介绍实做比较常用闭包的几种模式 工厂模式 上个章节有介绍到,...
出於书本 Chapter 7. Passwords 话说... 书本在讲解各种密码破解的相关知识时,...
上一回我们说旅行推销员问题(TSP)是一个NP困难问题,没有快速的演算法可以解决。 那一个问题怎样叫...
本节来说明AR中虚拟讯息的种类和它的好处,前面有稍微提到,AR是将虚拟讯息/物件叠加在真实世界中,而...