iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Modern Web

用30天更加認識 React.js 這個好朋友系列 第 16

Day16-Redux 篇-認識 Redux Toolkit

  • 分享至 

  • xImage
  •  

在這篇文章中,我們要來認識一個函式庫: Redux Toolkit。

Redux Toolkit 官網

Redux Toolkit 是什麼?

不知道讀者有沒有感覺到寫 Redux 寫久了,像 Actions、Reducers 那些函式很像模板,就是格式都很相似,而且重複性有點高,然後我們常常會拆分成 actions、reducers、action types 各自為一個檔案。

而 Redux Toolkit 的出現可以幫助你更有效率撰寫 Redux 的一個 library,它提供了一些 API 讓你更方便的建立 Store、Actions 和 Reducers 並減少重複性質的程式碼。

以下介紹幾個 API 的作用,在下篇範例中我們將會實際使用它們其中幾個。

configureStore()

功用和 createStore 一樣可以建立 Store,但還可以結合 reducers、middleware。

範例:

import { configureStore } from '@reduxjs/toolkit'

import rootReducer from './reducers'

const store = configureStore({ reducer: rootReducer })

createAction()

建立 action creator 的函式。放在 createAction() 裡面的參數會自動變成 action type,如範例中的 counter/increment,在產生 increment 這個 action creator 之後,將參數帶進這個 action creator 會變成 action 的 payload。

範例:

import { createAction } from '@reduxjs/toolkit'

const increment = createAction('counter/increment')

let action = increment()
// { type: 'counter/increment' }

action = increment(3)
// returns { type: 'counter/increment', payload: 3 }

createReducer()

使用它在撰寫 reducer 的時候可以不用再用 switch case 語法,並且它的語法底層加入了 immer,因此可以使用會有 side effect 的寫法去變更 state,它背後會再幫你轉成 「immutable」的方式。

範例:

import { createAction, createReducer } from '@reduxjs/toolkit'

const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction('counter/incrementByAmount')

const initialState = { value: 0 }

const counterReducer = createReducer(initialState, (builder) => {
  builder
    .addCase(increment, (state, action) => {
      state.value++
    })
    .addCase(decrement, (state, action) => {
      state.value--
    })
    .addCase(incrementByAmount, (state, action) => {
      state.value += action.payload
    })
})

createSlice()

將一個 slice 的 name、初始化的 state、reducer、action 統一在一個地方建立,並會產生 action creators 和 action type。

import { createSlice } from '@reduxjs/toolkit'

const initialState = { value: 0 }

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment(state) {
      state.value++
    },
    decrement(state) {
      state.value--
    },
    incrementByAmount(state, action) {
      state.value += action.payload
    },
  },
})

export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer

createAsyncThunk

用來處理非同步,會接受一個 action type 和一個回傳 promise 的 callback function,最後回傳一個 thunk action creator。

import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { userAPI } from './userAPI'

// First, create the thunk
const fetchUserById = createAsyncThunk(
  'users/fetchByIdStatus',
  async (userId, thunkAPI) => {
    const response = await userAPI.fetchById(userId)
    return response.data
  }
)

// Then, handle actions in your reducers:
const usersSlice = createSlice({
  name: 'users',
  initialState: { entities: [], loading: 'idle' },
  reducers: {
    // standard reducer logic, with auto-generated action types per reducer
  },
  extraReducers: (builder) => {
    // Add reducers for additional action types here, and handle loading state as needed
    builder.addCase(fetchUserById.fulfilled, (state, action) => {
      // Add user to the state array
      state.entities.push(action.payload)
    })
  },
})

// Later, dispatch the thunk as needed in the app
dispatch(fetchUserById(123))

下一篇將會針對原本用 Redux 寫的程式碼範例用 Redux Toolkit 去做改寫。

2023/03/02 補充-如何在 createSlice 中在一個 reducer 內使用另一個 reducer

可以參考官網提供的以下範例,使用 [slice 名稱].caseReducers.[reducer 名稱] 即可使用指定的 reducer。

const slice = createSlice({
  name: 'test',
  initialState: 0,
  reducers: {
    increment: (state, action: PayloadAction<number>) => state + action.payload,
  },
})

// also available:
slice.caseReducers.increment(0, { type: 'increment', payload: 5 })

上一篇
Day15-Redux 篇-實作範例
下一篇
Day17-Redux 篇-用 Redux Toolkit 實作範例
系列文
用30天更加認識 React.js 這個好朋友33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

1
janlin002
iT邦好手 1 級 ‧ 2023-03-03 15:12:55

有在持續更新的文章,必須推爆/images/emoticon/emoticon12.gif

harry xie iT邦研究生 1 級 ‧ 2023-03-03 16:19:46 檢舉

咦?請問你怎麼知道的

難道是更新文章的話我的追蹤者們都會收到通知嗎XD

janlin002 iT邦好手 1 級 ‧ 2023-03-03 17:06:00 檢舉

沒有拉,我最近面試被問到Redux Toolkit,想說來了解一下

harry xie iT邦研究生 1 級 ‧ 2023-03-03 18:44:29 檢舉

哈哈好,希望對你有幫助~

我要留言

立即登入留言