如果一路跟到這邊的話應該會覺得處理上很容易,事實上確實也是如此,因為前面的規劃已經完成了,包含非同步事件的處理,這些也就只是 javascript 的基本觀念而已,所以我們將之前做好的 pokemonSlice 也搬遷過來吧!
我們先確認一下有沒有安裝 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 回傳的資料完成一個簡單的換頁。
是說 pokemonSlice.js
沒有定義 selectPokemon
感謝你的提醒~我整段上錯檔案了,正確的範例在我的github 連結。