iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
自我挑戰組

30天深入淺出Redux系列 第 23

Redux 深入淺出 - [ Day 23 ] React Redux 非同步處理

  • 分享至 

  • xImage
  •  

如果一路跟到這邊的話應該會覺得處理上很容易,事實上確實也是如此,因為前面的規劃已經完成了,包含非同步事件的處理,這些也就只是 javascript 的基本觀念而已,所以我們將之前做好的 pokemonSlice 也搬遷過來吧!

https://media.giphy.com/media/fSvqyvXn1M3btN8sDh/giphy.gif

我們先確認一下有沒有安裝 Axios,如果沒有的話先行安裝:

npm install axios
or
yarn add axios

那麼我們先從 pokemonSlice 開始移植,一樣於 src/features/slices 路徑下新增 pokemonSlice.js 的檔案如下:

// src/features/slices/pokemonSlice.js
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"
import axios from "axios"

const initialState = {
  loading: false,
  data: [],
  error: ''
}

export const fetchPokes = createAsyncThunk('pokemon/fetchPokes', (url) => {
  return axios
    .get(url)
    .then(response => response.data)
})

const pokemonSlice = createSlice({
  name: 'pokemon',
  initialState,
  reducers: {},
  // 這裡就按常規套路走,在 createAsyncThunk 之後可以接的有 pending, fulfilled, rejected 三種情況
  extraReducers: builder => {
    builder.addCase(fetchPokes.pending, state => {
      state.loading = true
      return state;
    })
    builder.addCase(fetchPokes.fulfilled, (state, action) => {
      state.loading = false
      state.data = action.payload
      state.error = ''
      return state;
    })
    builder.addCase(fetchPokes.rejected, (state, action) => {
      state.loading = false
      state.data = []
      state.error = action.error.message
      return state
    })
  }
})
// 方便辨識的處理
export const selectPokemon = (state) => state.pokemon;

export default pokemonSlice.reducer

完成後不要忘記於 store 裏面做調整:

// src/features/store.js
import { configureStore } from '@reduxjs/toolkit'
import assetsSlice from './slices/assetsSlice'
import cakeSlice from './slices/cakeSlice'
import coffeeBeanSlice from './slices/coffeeBeanSlice'
import coffeeSlice from './slices/coffeeSlice'
import pokemonSlice from './slices/pokemonSlice'

const store = configureStore({
  reducer: {
    coffee: coffeeSlice,
    coffeeBean: coffeeBeanSlice,
    cake: cakeSlice,
    assets: assetsSlice,
    pokemon: pokemonSlice
  }
})

export default store

接著我們來處理畫面,先讓第一頁的資訊能在頁面上瀏覽,我這裡將每筆資料筆數改為 10 個,方便個為官看,因為後面我們會來做上下頁換頁的功能,所以會先以簡單的形式顯現資料與圖案,那麼我們首先新增一個 component 叫 Pokemons 如以下:

// src/components/Pokemons.jsx
import React from 'react'
import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchPokes, selectPokemon } from '../features/slices/pokemonSlice'

const Pokemons = () => {
  const pokemon = useSelector(selectPokemon)
  const dispatch = useDispatch()
	// 這裡透useEffect來打api,並判斷出使情況下做此處理
  useEffect(() => {
    if(pokemon.data.length === 0) {
      dispatch(fetchPokes(`https://pokeapi.co/api/v2/pokemon?offset=0&limit=10`))
    }
  }, [pokemon.data.length])

  console.log('pokeData', pokemon);

  return (
    <div>
      <h4>Pokemon List</h4>
      <ul>
        {pokemon.data?.results?.map((pokemon) => (
          <li key={pokemon.url}>
            <img 
              alt={pokemon.name} 
              width="200px" 
              // 這裡取圖案的 url 是齊全的
              src={`https://img.pokemondb.net/artwork/large/${pokemon.name}.jpg`} 
            />
            <p>{pokemon.name}</p>
          </li>
        ))}
      </ul>
    </div>
  )
}

export default Pokemons

處理完成後我們於 App 做以下的調整,先將我們先前的咖啡功能碼掉,因為現在用不到了,然後引入剛剛完成的 Pokemons,如以下:

// src/App.jsx
import AssetsBlock from "./components/AssetsBlock"
import CakeBlock from "./components/CakeBlock"
import CoffeeBeanBlock from "./components/CoffeeBeanBlock"
import CoffeeBlock from "./components/CoffeeBlock"
import Pokemons from "./components/Pokemons"

function App() {

  return (
    <div className="container">
      <h1>Restaurant Record</h1>
      {/* <AssetsBlock/>
      <CoffeeBlock/>
      <CoffeeBeanBlock/>
      <CakeBlock/> */}
      <Pokemons/>
    </div>
  )
}

export default App

這時候畫面應該會看到 1~10 編號的 pokemon 列表,那麼恭喜你已經完成和前兩個專案一樣的功能了。

那麼,今天的內容就先到這邊,下一篇我們來利用 Api 回傳的資料完成一個簡單的換頁。


上一篇
Redux 深入淺出 - [ Day 22 ] React Redux 資金功能設定
下一篇
Redux 深入淺出 - [ Day 24 ] React Redux Pokemon 換頁功能
系列文
30天深入淺出Redux31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Dylan
iT邦新手 1 級 ‧ 2023-05-24 22:36:23

是說 pokemonSlice.js 沒有定義 selectPokemon

LucianoLee iT邦研究生 5 級 ‧ 2023-05-25 10:45:02 檢舉

感謝你的提醒~我整段上錯檔案了,正確的範例在我的github 連結

我要留言

立即登入留言