useReducer によるページネーションの状態管理
useReducerでページネーション機能を実装した時のメモです.
the official document によると、useReducer は useState の代替です. useReducer が useState よりも優れている主な状況が 2 つあります.
と
ページ番号とページに要素を描画する配列、その他のページネーション関連の状態を同時に管理する必要があるため、useReducer を使用することにしました.
useReducer の基本的な構文は次のとおりです.
**(state, action) => newState ** タイプのレデューサーを受け取り、現在の状態とディスパッチのペアを返します.これは Redux と非常によく似た構文です.
これが実際のコードです.
1️) 初期状態を設定
2) レデューサーを定義する
if ステートメントの代わりに switch ステートメントを使用できます.
3) コンポーネント関数内で呼び出す
4) タイプごとにディスパッチメソッドを呼び出す
タイプ:「ページネーション」
タイプ: 「クエリ」
タイプ:「更新」
SearchBooksComponents のコード スニペット全体を次に示します.
読んでくれてありがとう :)
感想など頂けたら嬉しいです!
元の記事は here です
useReducer とは何か、いつ使用するか
the official document によると、useReducer は useState の代替です. useReducer が useState よりも優れている主な状況が 2 つあります.
when you have complex state logic that involves multiple sub-values
と
when the next state depends on the previous one
ページ番号とページに要素を描画する配列、その他のページネーション関連の状態を同時に管理する必要があるため、useReducer を使用することにしました.
基本構文
useReducer の基本的な構文は次のとおりです.
const [state, dispatch] = useReducer(reducer, initialState)
**(state, action) => newState ** タイプのレデューサーを受け取り、現在の状態とディスパッチのペアを返します.これは Redux と非常によく似た構文です.
実際のコードを使用した段階的な手順
これが実際のコードです.
1️) 初期状態を設定
const initialState = {
results: [],
query: "",
totalItems: 0,
startIndex: 0,
page: 1,
};
2) レデューサーを定義する
const searchReducer = (currntState, action) => {
if (action.type === "UPDATE") {
return {
...currntState,
results: action.results,
totalItems: action.totalItems,
};
}
if (action.type === "QUERY") {
return {
...currntState,
query: action.query,
startIndex: 0,
page: 1,
};
}
if (action.type === "PAGINATION") {
return {
...currntState,
page: action.page,
startIndex: (action.page - 1) * 20 - 1,
};
}
};
if ステートメントの代わりに switch ステートメントを使用できます.
3) コンポーネント関数内で呼び出す
const [searchState, dispatchSearch] = useReducer(searchReducer, initialState);
4) タイプごとにディスパッチメソッドを呼び出す
タイプ:「ページネーション」
const pageChangeHandler = (event, newValue) => {
dispatchSearch({ type: "PAGINATION", page: newValue });
};
タイプ: 「クエリ」
const searchHandler = () => {
setInit(false);
sendGetRequest(searchInputRef.current.value);
dispatchSearch({
type: "QUERY",
query: searchInputRef.current.value,
});
searchInputRef.current.value = "";
};
タイプ:「更新」
useEffect(() => {
if (loadedBooksData && !init) {
dispatchSearch({
type: "UPDATE",
results: loadedBooksData.results,
totalItems: loadedBooksData.totalItems,
});
}
}, [loadedBooksData, init]);
SearchBooksComponents のコード スニペット全体を次に示します.
import { Fragment, useRef, useReducer, useEffect, useState } from "react";
import { Route, Routes } from "react-router-dom";
import SearchIcon from "[@mui/icons-material](http://twitter.com/mui/icons-material)/Search";
import Pagination from "[@mui/material](http://twitter.com/mui/material)/Pagination";
import useHttp from "../hooks/use-http";
import BookList from "./BookList";
import LoadingSpinner from "../UI/LoadingSpinner";
import ErrorMessage from "../UI/ErrorMessage";
import BookDetail from "./BookDetail";
import { getSearchBooks } from "../lib/api";
import classes from "./SearchBooks.module.css";
const initialState = {
results: [],
query: "",
totalItems: 0,
startIndex: 0,
page: 1,
};
const searchReducer = (currntState, action) => {
if (action.type === "UPDATE") {
return {
...currntState,
results: action.results,
totalItems: action.totalItems,
};
}
if (action.type === "QUERY") {
return {
...currntState,
query: action.query,
startIndex: 0,
page: 1,
};
}
if (action.type === "PAGINATION") {
return {
...currntState,
page: action.page,
startIndex: (action.page - 1) * 20 - 1,
};
}
};
const SearchBooks = () => {
return (
<Routes>
<Route path="" element={<SearchBooksComponents />} />
<Route path=":bookId/*" element={<BookDetail />} />
</Routes>
);
};
export default SearchBooks;
const SearchBooksComponents = () => {
const [init, setInit] = useState(true);
const [searchState, dispatchSearch] = useReducer(searchReducer, initialState);
const searchInputRef = useRef("");
const {
sendRequest: sendGetRequest,
status,
data: loadedBooksData,
error,
} = useHttp(getSearchBooks, true);
const searchHandler = () => {
setInit(false);
sendGetRequest(searchInputRef.current.value);
dispatchSearch({
type: "QUERY",
query: searchInputRef.current.value,
});
searchInputRef.current.value = "";
};
const pageChangeHandler = (event, newValue) => {
dispatchSearch({ type: "PAGINATION", page: newValue });
};
useEffect(() => {
if (searchState.query && !init) {
sendGetRequest(searchState.query, searchState.startIndex);
}
}, [searchState.query, searchState.startIndex, sendGetRequest, init]);
useEffect(() => {
if (loadedBooksData && !init) {
dispatchSearch({
type: "UPDATE",
results: loadedBooksData.results,
totalItems: loadedBooksData.totalItems,
});
}
}, [loadedBooksData, init]);
return (
<Fragment>
<div className={classes.search}>
<input type="text" placeholder="search books" ref={searchInputRef} />
<button type="submit" onClick={searchHandler}>
<SearchIcon sx={{ fontSize: 35 }} />
</button>
</div>
{status === "loading" && !init && <LoadingSpinner />}
{status === "completed" && error && <ErrorMessage />}
{status === "completed" && !error && (
<Fragment>
<BookList results={searchState.results} />
<div className={classes.pagination}>
<Pagination
count={Math.ceil(searchState.totalItems / 20)}
page={searchState.page}
onChange={pageChangeHandler}
/>
</div>
</Fragment>
)}
</Fragment>
);
};
読んでくれてありがとう :)
感想など頂けたら嬉しいです!
元の記事は here です
Reference
この問題について(useReducer によるページネーションの状態管理), 我々は、より多くの情報をここで見つけました https://dev.to/lada496/a-pagination-state-management-with-usereducer-5fc4テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol