當發起 dispatch 到 UI 更新之間做什麼事情
希望 dispath 有能力可以再去做其他事情(所以會在過程中去做一些邏輯)
希望過程中可以再做些事情(UI 從 dispatch 到真正渲染之間)
Middleware
實際上是一個 function
next 是 dispatch 的意思,next 所代表的是傳入 action ,會調用下一個 dispatch 來執行所傳入的這個 action
以官網範例:
1 2 3 4 5 6 const logger = store => nextDispatch => action => { console .log ('dispatching' , action) let result = nextDispatch (action) console .log ('next state' , store.getState ()) return result }
在專案建立 位置:src / middleware
簡易說明 在 return 最後的 function 之前,第二個 function 就是將原有的 dispatch 丟到最後的 function 中,再 return 出去。 在取的 dispatch 之前,會再拿到 store 也是使用 api 時候會回傳進來的東西。 當 middleware 建立好之後,要到 store 當案進行宣告
combineReducers
建立的 slice夾中可能會有多個 reducer,例如 todoReducer, friendReducer, phoneReduce…
Middleware 與 store 的建立
在 middleware 去寫功能的時後,主要分為兩個部分
在 dispach 之前要做什麼事情
在 dispach 之後要做什麼事情
RTK Query 使用 middileware 去定義我們的 reducers 會分成多個階段
pedding
success
error 針對每一次 API 取資料,加入到 reducers 中,此方式會使得 reducer 變得龐大、複雜。 RTK Query 協助將所有關於 call API 或是 獲取資料過程的功能,將他包裝成一個攻能,並且完全獨立於 reducer 或 redux 的邏輯
可以使用 RTK Query 中的 hook 去獲取當前 data , error 狀態等官方文件
建立 api educerPath => 最後會產生 reducer ,所包含內容會有 pedding, success,error 等狀態 baseQuery => 就是放入 baseUrl endpoint => 放入 query 資訊 any : 表示會回傳一個 any 結果 string : 需要傳入 string 的 input
json placeholder
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' export const todoApiService = createApi ({ reducerPath : 'todoApi' , baseQuery : fetchBaseQuery ({ baseUrl : 'https://jsonplaceholder.typicode.com/' }), endpoints : (builder ) => ({ getTodoApi : builder.query <any, string>({ query : (id ) => `todos/${id} ` , }) }), }) export const { useGetTodoApiQuery } = todoApiService
至 store 新增 todoAPI
引用 API hook import { useGetTodoApiQuery } from './services/todoApi';
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 import './App.css' ;import styled from 'styled-components' import { useAppSelector, useAppDispatch } from './hooks' ;import { addTodo, addTimestamp } from './slice/todo' import React , { useState } from 'react' ;import { useGetTodoApiQuery } from './services/todoApi' ;const Wrapper = styled.div ` padding: 1.5rem; ` const Title = styled.h2 ` font-weight: 900; margin-top: 2rem; ` const NoteInput = styled.input ` width: 100%; height: 40px; border-radius: 10px; padding-left: .5rem; box-sizing: border-box; ` const SubmitBtn = styled.button ` width: 100%; box-sizing: border-box; height: 40px; background: #000; display: flex; justify-content: center; align-items: center; color: #fff; border-radius: 10px; border: 0; font-weight: 900; margin-top: 1rem; :active { background: #000000be; } ` const Item = styled.div ` margin-top: 1rem; > b { margin-right: .5rem; } ` function App ( ) { const todoReducer = useAppSelector (state => state.todoReducer ) const todoList = todoReducer.todoList const dispatch = useAppDispatch () const [text, setText] = useState ("" ) const { data, error, isLoading } = useGetTodoApiQuery ('1' ) console .log ('data:' , data) console .log ('error:' , error) console .log ('isLoading:' , isLoading) const { userId = 'N/A' , title = 'N/A' } = data || {} return ( <Wrapper > <Title > TODO LIST</Title > <NoteInput type ="text" value ={text} onChange ={(e: React.ChangeEvent <HTMLInputElement > ) => { setText(e.target.value) }} /> <SubmitBtn onClick ={() => { if (text === '') { alert('請輸入TODO內容') return } dispatch(addTodo(text)) setText('') }}> Submit </SubmitBtn > <SubmitBtn onClick ={() => { dispatch(addTimestamp()) }}> Record Timestamp </SubmitBtn > <Title > List</Title > { todoList.map((todo, index) => { return <Item key ={todo} > <b > {index + 1}</b > {todo} </Item > }) } <Title > List2</Title > { isLoading && <p > 正在載入資料...</p > } { !isLoading && ( <div > {/* <p > User ID:{data?.userId}</p > <p > Usr Title:{data?.title}</p > */} <p > User ID:{userId}</p > <p > Usr Title:{title}</p > </div > ) } </Wrapper > ); } export default App;
若是使用 react thunk
這裡的 middleware 的 reducer 中的 status 要自己去定義
優點:可以完全掌控自己 reducer 的內容
但相對也會較為繁瑣