iT邦幫忙

2022 iThome 鐵人賽

DAY 28
0
Modern Web

你 React 了嗎? 30 天解鎖 React 技能系列 第 28

[DAY 28] Redux Toolkit 非同步操作createAsyncThunk

  • 分享至 

  • xImage
  •  

cover

做前端時一定會碰到非同步操作,本篇將使用 axios 搭配 Redux Toolkit 來作範例串接 API,可以先將 axios 環境安裝起來


安裝 Axios

// npm 
npm i axios

// yarn
yarn add axios

依自己喜好去安裝 axios


範例:渲染出 json 資料

簡單解說一下流程

  • 新增一個 json 檔
  • Axios 串接
  • 創建 store
  • 外層包覆 Provider
  • createAsyncThunk 操作非同步
  • 取得 store 資料,渲染畫面

新增一個 json 檔

public/todoList.json

{
  "data": [
    { "id": 1, "text": "起床" },
    { "id": 2, "text": "刷牙洗臉" },
    { "id": 3, "text": "吃早餐" },
    { "id": 4, "text": "上班" }
  ]
}

在 public 新增一個要被渲染的 json 格式資料


Axios 串接

api/todoList.js

import axios from "axios";
export const getData = () => {
  return axios.get('/todoList.json');
}

新增 API 資料夾,使用 axios 串接剛剛的 json,如呼叫 getData 將會回傳 json 裡的資料


創建 store

store/index.js

import { configureStore } from "@reduxjs/toolkit";
import todoReducer from "./slice/todo";

export default configureStore({
  reducer: {
    todo: todoReducer
  }
});

創建 store,並載入 slice 供 store 使用


外層包覆 Provider

src/App.js

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

export default function App() {
  return (
    <Provider store={store}>
      <Todo />
    </Provider>
  );
}

載入 Providerstore,Provider 組件傳入 store

包在 Provider 裡的組件都可以使用 store


createAsyncThunk 操作非同步

store/slice/todo.js

import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { getData } from "../../api";

export const fetchData = createAsyncThunk("todo/fetchTodo", async () => {
  const response = await getData();
  return response.data.data;
});

export const todoSlice = createSlice({
  name: "todo",

  initialState: {
    loading: false,
    entities: []
  },

  reducers: {},

  extraReducers: {
    [fetchData.pending]: (state) => {
      state.loading = true;
    },

    [fetchData.fulfilled]: (state, { payload }) => {
      state.loading = false;
      state.entities = payload;
    },

    [fetchData.rejected]: (state) => {
      state.loading = false;
    }
  }
});

export const selectTodo = (state) => state.todo;
export default todoSlice.reducer;

在 slice 的地方引用,並使用 createAsyncThunk 操作非同步

我們設定了 loading、entities,在取得非同步資料完成時,loading 會變 false,並將資料傳遞給 entities

createAsyncThunk:在 Redux Toolkit 要呼叫非同步,需要使用 createAsyncThunk 方法

createAsyncThunk 接受兩個參數,第一個為 action type 字串,第二個為返回的 Promise,並生成一個pending、 fulfilledrejected ,分派 action type 的 thunk

createAsyncThunk(type string, promise)

extraReducers:因為非同步的函式不在 createSlice 裡面,如果要在 createSlice 中監聽這些 action type,需要在 extraReducers 使用


取得 store 資料,渲染畫面

src/Todo.js

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchData, selectTodo } from "./store/slice/todo";

function Todo() {
  const dispatch = useDispatch();
  const { entities, loading } = useSelector(selectTodo);

  useEffect(() => {
    dispatch(fetchData());
  }, [dispatch]);

  if (loading) return <p>Loading...</p>;

  return (
    <div>
      <h1>今日行程</h1>
      <ul>
        {entities.map((item) => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>
    </div>
  );
}

export default Todo;

useDispatch呼叫在 store 裡的 fetchData,並取得 api 回傳的資料

useSelector取得 store 裡的 state,用 map 渲染,資料就成功渲染在畫面囉!!

example

打開 codesandbox 程式碼範例 看看吧!!


結語

這邊的範例是讀取 json,當然你也可以使用 API URL 串接,一起練習看看吧~

Redux Toolkit 的部分就到這篇告一段落囉!!/images/emoticon/emoticon12.gif


Reference

Using Redux Toolkit’s createAsyncThunk


本文將同步更新至我的部落格
Lala 的前端大補帖



上一篇
[DAY 27] Redux Toolkit 管理組件的共用資料
下一篇
[DAY 29] useReducer 處理複雜邏輯的 state
系列文
你 React 了嗎? 30 天解鎖 React 技能30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言