Redux的使用

到如今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>
          <input
            type="number"
            value={depositAmount}
            onChange={(e) => setDepositAmount(+e.target.value)}
          />
          <select
            value={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>
          <input
            type="number"
            value={withdrawalAmount}
            onChange={(e) => setWithdrawalAmount(+e.target.value)}
          />
          <button onClick={handleWithdrawal}>
            Withdraw {withdrawalAmount}
          </button>
        </div>

        <div>
          <label>Request loan</label>
          <input
            type="number"
            value={loanAmount}
            onChange={(e) => setLoanAmount(+e.target.value)}
            placeholder="Loan amount"
          />
          <input
            value={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”中。

redux toolkit实现案例

accountSlice如下:

import { createSlice } from "@reduxjs/toolkit";

const initialState = {
  balance: 0,
  loan: 0,
  loanPurpose: "",
  isLoading: false,
};

const accountSlice = createSlice({
  name: "account",
  initialState,
  reducers: {
    deposit(state, action) {
      state.balance = state.balance + action.payload;
      state.isLoading = false;
    },

    withdraw(state, action) {
      state.balance = state.balance - action.payload;
    },

    requestLoan: {
      prepare(amount, purpose) {
        return {
          payload: { amount, purpose },
        };
      },

      reducer(state, action) {
        if (state.loan > 0) return;
        state.loan = action.payload.amount;
        state.loanPurpose = action.payload.loanPurpose;
        state.balance = state.balance + action.payload.amount;
      },
    },

    payLoan(state, action) {
      state.loan = 0;
      state.loanPurpose = "";
      state.balance = state.balance - state.loan;
    },

    convertingCurrency(state) {
      state.isLoading = true;
    },
  },
});

export const { withdraw, requestLoan, payLoan } = accountSlice.actions;

export default accountSlice.reducer;

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();
    const converted_deposit = data.rates.USD;
    dispatch({ type: "account/deposit", payload: converted_deposit });
  };
}

custom如下: 

import { createSlice } from "@reduxjs/toolkit";
const initialState = {
  fullName: "",
  nationalID: "",
  createdAt: "",
};

const customerSlice = createSlice({
  name: "customer",
  initialState,
  reducers: {
    createCustomer: {
      prepare(fullName, nationalID, createAt) {
        return {
          payload: {
            fullName,
            nationalID,
            createAt,
          },
        };
      },

      reducer(state, action) {
        state.fullName = action.payload.fullName;
        state.nationalID = action.payload.nationalID;
        state.createdAt = action.payload.createdAt;
      },
    },

    updateName(state, action) {
      state.fullName = action.payload;
    },
  },
});

export default customerSlice.reducer;

export const { createCustomer, updateName } = customerSlice.actions;

有如下好处: 

注意:其中chunk部分仍然是我们自己实现的 ;export时reducer和actions可以直接借助slice导出了。

store.js如下所示:

import { configureStore } from "@reduxjs/toolkit";
import customerReducer from "./features/customer/customerSlice";
import accountReducer from "./features/account/accountSlice";

const store = configureStore({
  reducer: {
    customer: customerReducer,
    account: accountReducer,
  },
});

export default store;

最新版的 react-redux 使用方法如下: 首先,确保你的项目已经安装了 react-redux 依赖包。你可以使用以下命令安装它: ``` npm install react-redux ``` 或 ``` yarn add react-redux ``` 接下来,你需要创建一个 Redux store。你可以使用 Redux Toolkit 来简化这个过程。首先,导入 `configureStore` 和 `getDefaultMiddleware` 函数: ``` import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit'; ``` 然后,创建一个 rootReducer 来合并你的所有 reducer: ``` import { combineReducers } from 'redux'; const rootReducer = combineReducers({ // 这里是你的 reducer }); ``` 接着,使用 `configureStore` 函数创建 Redux store。你可以通过传入一个对象来配置 store,例如指定 reducer、middleware 等等。以下是一个示例: ``` const store = configureStore({ reducer: rootReducer, middleware: getDefaultMiddleware() }); ``` 现在,你可以使用 `<Provider>` 组件来将 Redux store 提供给你的整个应用程序。在你的根组件中,导入 `<Provider>` 组件和你的 Redux store,然后将其包裹在应用的最外层: ``` import { Provider } from 'react-redux'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') ); ``` 通过将 Redux store 提供给整个应用程序,你可以在应用的任何地方使用 `useSelector` 和 `useDispatch` 钩子来访问 Redux store 中的状态和分发 action。例如,在你的组件中,你可以这样使用: ``` import { useSelector, useDispatch } from 'react-redux'; const MyComponent = () => { const counter = useSelector(state => state.counter); const dispatch = useDispatch(); // 使用 counter 和 dispatch }; ``` 这就是最新版的 react-redux使用方法。你可以根据你的具体需求,自定义配置和使用其他相关的 react-redux API。希望对你有帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值