微信导航网站模板seo联盟
到如今redux的已经不是react程序中必须的一部分内容了,
我们应该在本地需要大量更新全局变量时才使用它!
redux vs reducer
reducer的工作机制:
手动构造action对象传入dispatch函数中
dispatch函数将 action传入reducer当中
reducer结合当前state与action生成新的state
重新渲染
redux的工作机制:
其中store中有多个reducer
单独编写生成action的函数,集中管理action
传统实现案例
import { createStore } from "redux";const initialState = {balance: 0,loan: 0,loanPurpose: "",
};function reducer(state = initialState, action) {switch (action.type) {case "account/deposit":return {...state,balance: state.balance + action.payload,};case "account/withdraw":return {...state,balance: state.balance - action.payload,};case "account/requestLoan":if (state.loan > 0) return state;return {...state,loan: action.payload.amount,loanPurpose: action.payload.loanPurpose,balance: state.balance + action.payload.amount,};case "account/payLoan":return {...state,loan: 0,loanPurpose: "",balance: state.balance - state.loan,};default:return state;}
}const store = createStore(reducer);store.dispatch({ type: "account/deposit", payload: 500 });console.log(store.getState());
这与reducer的实现非常相似
我们不能一直手写类型,这非常不方便。所以要有相关函数来做这部分内容。
import { createStore } from "redux";const initialState = {balance: 0,loan: 0,loanPurpose: "",
};function reducer(state = initialState, action) {switch (action.type) {case "account/deposit":return {...state,balance: state.balance + action.payload,};case "account/withdraw":return {...state,balance: state.balance - action.payload,};case "account/requestLoan":if (state.loan > 0) return state;return {...state,loan: action.payload.amount,loanPurpose: action.payload.loanPurpose,balance: state.balance + action.payload.amount,};case "account/payLoan":return {...state,loan: 0,loanPurpose: "",balance: state.balance - state.loan,};default:return state;}
}const store = createStore(reducer);function deposit(payload) {return { type: "account/deposit", payload: payload };
}function withdraw(payload) {return { type: "account/withdraw", payload: payload };
}function requestLoan(payload) {return { type: "account/requestLoan", payload: payload };
}function payLoan(payload) {return { type: "account/payLoan" };
}store.dispatch(deposit(500));
store.dispatch(withdraw(200));
store.dispatch(requestLoan({ amount: 1000, loanPurpose: "Buy a car" }));
store.dispatch(payLoan());
redux中一般store中有多个reducer,我们可以组织代码如下:
accountSlice文件中放置account相关的state:
const initialState = {balance: 0,loan: 0,loanPurpose: "",
};export default function accountReducer(state = initialState, action) {switch (action.type) {case "account/deposit":return {...state,balance: state.balance + action.payload,};case "account/withdraw":return {...state,balance: state.balance - action.payload,};case "account/requestLoan":if (state.loan > 0) return state;return {...state,loan: action.payload.amount,loanPurpose: action.payload.loanPurpose,balance: state.balance + action.payload.amount,};case "account/payLoan":return {...state,loan: 0,loanPurpose: "",balance: state.balance - state.loan,};default:return state;}
}export function deposit(amount) {return { type: "account/deposit", payload: amount };
}export function withdraw(amount) {return { type: "account/withdraw", payload: amount };
}export function requestLoan(payload) {return { type: "account/requestLoan", payload: payload };
}export function payLoan() {return { type: "account/payLoan" };
}
customerSlice文件中放置customer相关的state:
const initialCustormerState = {fullName: "",nationalID: "",createdAt: "",
};export default function customerReducer(state = initialCustormerState, action) {switch (action.type) {case "customer/createCustomer":return {...state,fullName: action.payLoad.fullName,nationalID: action.payLoad.nationalID,createdAt: action.payLoad.createdAt,};case "customer/updateName":return {...state,fullName: action.payLoad.fullName,};default:return state;}
}export function createCustomer(fullName, nationalID) {return {type: "customer/createCustomer",payLoad: {fullName: fullName,nationalID: nationalID,createdAt: new Date().toISOString(),},};
}export function updateName(fullName) {return {type: "account/updateName",payLoad: fullName,};
}
store文件中对reducer进行组合:
import { createStore, combineReducers } from "redux";
import customerReducer from "./features/customer/customerSlice";
import accountReducer from "./features/account/accountSlice";const rootReducer = combineReducers({customer: customerReducer,account: accountReducer,
});const store = createStore(rootReducer);export default store;
导入index.js中即可:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import store from "./store";const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<React.StrictMode><App /></React.StrictMode>
);
然后将redux与react联系起来,这与contextAPI非常相似,提供一个Provider,并且传入store:
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<React.StrictMode><Provider store={store}><App /></Provider></React.StrictMode>
);
然后各个组件中就可以通过useSelector hook获取store中的state,通过useDispatch hook就可以获取dispatch传递action
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { deposit, payLoan, requestLoan, withdraw } from "./accountSlice";function AccountOperations() {const [depositAmount, setDepositAmount] = useState("");const [withdrawalAmount, setWithdrawalAmount] = useState("");const [loanAmount, setLoanAmount] = useState("");const [loanPurpose, setLoanPurpose] = useState("");const [currency, setCurrency] = useState("USD");const { loan: currentLoan, loanPurpose: currencyLoanPurpose } = useSelector((store) => store.account);const dispatch = useDispatch();function handleDeposit() {if (!depositAmount) return;dispatch(deposit(depositAmount));setDepositAmount("");}function handleWithdrawal() {if (!withdrawalAmount) return;dispatch(withdraw(withdrawalAmount));setWithdrawalAmount("");}function handleRequestLoan() {if (!loanAmount || !loanPurpose) return;dispatch(requestLoan(loanAmount, loanPurpose));setLoanAmount("");setLoanPurpose("");}function handlePayLoan() {dispatch(payLoan());}return (<div><h2>Your account operations</h2><div className="inputs"><div><label>Deposit</label><inputtype="number"value={depositAmount}onChange={(e) => setDepositAmount(+e.target.value)}/><selectvalue={currency}onChange={(e) => setCurrency(e.target.value)}><option value="USD">US Dollar</option><option value="EUR">Euro</option><option value="GBP">British Pound</option></select><button onClick={handleDeposit}>Deposit {depositAmount}</button></div><div><label>Withdraw</label><inputtype="number"value={withdrawalAmount}onChange={(e) => setWithdrawalAmount(+e.target.value)}/><button onClick={handleWithdrawal}>Withdraw {withdrawalAmount}</button></div><div><label>Request loan</label><inputtype="number"value={loanAmount}onChange={(e) => setLoanAmount(+e.target.value)}placeholder="Loan amount"/><inputvalue={loanPurpose}onChange={(e) => setLoanPurpose(e.target.value)}placeholder="Loan purpose"/><button onClick={handleRequestLoan}>Request loan</button></div>{currentLoan > 0 && (<div><span>Pay back {currentLoan} {currencyLoanPurpose}</span><button onClick={handlePayLoan}>Pay loan</button></div>)}</div></div>);
}export default AccountOperations;
middleware 与 redux chunk
由于store本身的局限性无法处理异步情况,所以在dispatch传递时,不直接到reducer中,而是先通过middle ware。而redux chunk就是reudx目前最流行的middle ware第三方库。
首先在store中进行middle ware的配置:
import { createStore, combineReducers, applyMiddleware } from "redux";
import { thunk } from "redux-thunk";
import customerReducer from "./features/customer/customerSlice";
import accountReducer from "./features/account/accountSlice";const rootReducer = combineReducers({customer: customerReducer,account: accountReducer,
});const store = createStore(rootReducer, applyMiddleware(thunk));export default store;
然后在action中进行异步情况的处理:
export function deposit(amount, currency) {if (currency === "USD") return { type: "account/deposit", payload: amount };return async function (dispatch, getState) {dispatch({ type: "account/convertingCurrency" });const res = await fetch(`https://api.frankfurter.app/latest?amount=${amount}&from=${currency}&to=USD`);const data = await res.json();console.log(data);const converted_deposit = data.rates.USD;dispatch({ type: "account/deposit", payload: converted_deposit });};
}
当我们返回的不是一个对象,而是一个函数时,redux就会意识到这个函数是一个“thunk”,redux就不会马上将其传递到store的reducer中,而是会运行这个函数“thunk”,并将dispatch和getState作为函数参数传递到函数“thunk”中。