iT邦幫忙

2021 iThome 鐵人賽

DAY 16
0
Modern Web

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

Day16-Redux 篇-認識 Redux Toolkit

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

Redux Toolkit 官網

Redux Toolkit 是什麼?

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 去做改寫。


上一篇
Day15-Redux 篇-實作範例
下一篇
Day17-Redux 篇-用 Redux Toolkit 實作範例
系列文
用30天更加認識 React.js 這個好朋友32

尚未有邦友留言

立即登入留言