iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
自我挑戰組

新手前端與真實世界的開發 feat.React 與他的夥伴系列 第 24

Day-24 專案演練 - 用跳窗來小試身手 redux

  • 分享至 

  • xImage
  •  

Day-24 專案演練 - 用跳窗來小試身手 redux

今天要來嘗試 redux,用的是 RTK(Redux Toolkit),可以先去官網看看這是個甚麼工具。因為第一次要引入近來,有點怕怕的,不然就先來試試做一個簡單一點的功能 :用 redux 來控制彈跳視窗的開合。

新增與安裝 RTK

先按照官網的指示安裝一下,使用 RTK 總共需要兩個包,一個是 react-redux 另一個是 reduxjs-toolkit :

npm install @reduxjs/toolkit react-redux

接著在 src 底下新增 redux 資料夾,接下來所有 redux 相關的東西都放在這,事不宜遲,馬上先把猶如 redux 靈魂般的 store 新增起來 :

store.ts

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

export const store = configureStore({
  reducer: {
    // 晚點要來放 reducer 的地方
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

接下來安裝在 index.tsx,引入 store 與 Provider,接上他的腿(?) :

index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import { ChakraProvider } from "@chakra-ui/react";
import { BrowserRouter } from "react-router-dom";

import App from "./App";
import "./index.css";
import { store } from "./redux/store";
import { Provider } from "react-redux";

const root = ReactDOM.createRoot(
  document.getElementById("root") as HTMLElement
);
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Provider store={store}> // 腿在這兒
        <ChakraProvider>
          <App />
        </ChakraProvider>
      </Provider>
    </BrowserRouter>
  </React.StrictMode>
);

包裝 hooks

為了少寫一點點程式碼,所以來做個 redux 的 hook,稍微包裝一下 dispatch 與 selector :

import { useDispatch, TypedUseSelectorHook, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";

export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

新增 slice

好,來新增一個負責 Modal 的 slice,就叫做 modalSlice,在 redux 資料夾底下新增一個 modalSlice,裡面要放兩個檔案,一個是 index.d.ts 用來定義型別,另一個就是本體叫做 modalSlice.ts :

index.d.ts

import { store } from "../store";

export type ModalState = {
  isOpen: boolean; // 目前只需要這個 state
};

export type RootState = ReturnType<typeof store.getState>;

modalSlice.ts

import { createSlice } from "@reduxjs/toolkit";
import type { PayloadAction } from "@reduxjs/toolkit";
import { ModalState, RootState } from "./index";

const initialState: ModalState = {
  isOpen: false,
};

const modalSlice = createSlice({
  name: "modal",
  initialState,
  reducers: {
    openModal: (state: ModalState, action: PayloadAction) => {
      state.isOpen = true;
    },
    closeModal: (state: ModalState, action: PayloadAction) => {
      state.isOpen = false;
    },
  },
});

export const { openModal, closeModal } = modalSlice.actions;
export const selectModalIsOpen = (state: RootState) => state.modalSlice.isOpen;
export default modalSlice.reducer;

放 reducer 進 store

做好了 slice,最後把 reducer 放回 store,前置作業就算完成了 :

import { configureStore } from "@reduxjs/toolkit";
import modalSlice from "./modalSlice/modalSlice";

export const store = configureStore({
  reducer: {
    modalSlice,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

在 UI 新增功能

回到 TodoPage ,等下要在 TodoPage 繼續做事,引入必要的工具 :

...
import { useAppSelector, useAppDispatch } from "../../redux/hooks";
import {
  selectModalIsOpen,
  openModal,
  closeModal,
} from "../../redux/modalSlice/modalSlice";
...

接著抓到剛剛在 modalSlice 裡面設定好的 isModalOpen,取代原本的 state :

...
const isOpen = useAppSelector(selectModalIsOpen);
  // const [isOpen, setIsOpen] = useState(false);
  ...

把 dispatch 給初始化,等一下要 action 還要用它 :

...
  const dispatch = useAppDispatch();
  ...

準備就緒之後,把報錯清掉,一步一步更新 UI, :

...
<TodoModal
        isOpen={isOpen}
        closeModal={() => dispatch(closeModal())} //這裡
        register={register}
        onSubmit={onSubmit}
        handleSubmit={handleSubmit}
        reset={reset}
      />
      ...

TodoModal 這邊有點改變 :

...
type Props = {
  isOpen?;
  closeModal; // 增加關窗 prop
  onSubmit;
  register;
  handleSubmit;
  reset;
};
...
onClick={closeModal} // 在叉叉上面放著
...

對照程式碼增減

新增 redux 之後程式碼暴增,原本要在 TodoPage 控制跳窗,只需要一點點程式碼而已 XD :

const [isOpen, setIsOpen] = useState(false); // 單靠 setIsOpen 走天下

repo

附上程式碼

結語

從新增彈跳視窗這個相對簡單的功能來暖身一下,覺得還滿合適的,我喜歡這樣用這樣的方法在新專案開始 RTK。


上一篇
Day-23 專案演練 - 狀態管理員 redux
下一篇
Day-25 專案演練 - 創造全局待辦清單 redux
系列文
新手前端與真實世界的開發 feat.React 與他的夥伴30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言