├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt └── src ├── App.js ├── Example1.js ├── Example2.js ├── PageButton.js ├── Post.js ├── User.js ├── api └── axios.js ├── index.css └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # "React Pagination Tutorial" 2 | 3 | --- 4 | 5 | ### Author Links 6 | 7 | 👋 Hello, I'm Dave Gray. 8 | 9 | ✅ [Check out my YouTube Channel with all of my tutorials](https://www.youtube.com/DaveGrayTeachesCode). 10 | 11 | 🚩 [Subscribe to my channel](https://bit.ly/3nGHmNn) 12 | 13 | ☕ [Buy Me A Coffee](https://buymeacoffee.com/DaveGray) 14 | 15 | 🚀 Follow Me: 16 | 17 | - [Twitter](https://twitter.com/yesdavidgray) 18 | - [LinkedIn](https://www.linkedin.com/in/davidagray/) 19 | - [Blog](https://yesdavidgray.com) 20 | - [Reddit](https://www.reddit.com/user/DaveOnEleven) 21 | 22 | --- 23 | 24 | ### Description 25 | 26 | 📺 [YouTube Video](https://youtu.be/9ZbdwL5NSuQ) for this repository. 27 | 28 | --- 29 | 30 | ### 💻 Source Code 31 | 32 | - 🔗 [React Pagination Tutorial - Completed Source Code](https://github.com/gitdagray/react_pagination) 33 | 34 | --- 35 | 36 | ### 🎓 Academic Honesty 37 | 38 | **DO NOT COPY FOR AN ASSIGNMENT** - Avoid plagiargism and adhere to the spirit of this [Academic Honesty Policy](https://www.freecodecamp.org/news/academic-honesty-policy/). 39 | 40 | --- 41 | 42 | ### 📚 Tutorial References 43 | 44 | - 🔗 [React Query: Paginated Queries](https://react-query.tanstack.com/guides/paginated-queries) 45 | - 🔗 [JSON Placeholder: Posts](https://jsonplaceholder.typicode.com/posts) 46 | - 🔗 [ReqRes.in: Users](https://reqres.in/api/users?page=1) 47 | 48 | ### ⚙ VS Code Extensions I Use: 49 | 50 | - 🔗 [ES7 React JS Snippets Extension](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) 51 | - 🔗 [vscode-icons VS Code Extension](https://marketplace.visualstudio.com/items?itemName=vscode-icons-team.vscode-icons) 52 | - 🔗 [Github Themes VS Code Extension](https://marketplace.visualstudio.com/items?itemName=GitHub.github-vscode-theme) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react_pagination", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "axios": "^0.27.2", 7 | "react": "^18.2.0", 8 | "react-dom": "^18.2.0", 9 | "react-query": "^3.39.1", 10 | "react-scripts": "5.0.1" 11 | }, 12 | "scripts": { 13 | "start": "react-scripts start", 14 | "build": "react-scripts build", 15 | "test": "react-scripts test", 16 | "eject": "react-scripts eject" 17 | }, 18 | "eslintConfig": { 19 | "extends": [ 20 | "react-app", 21 | "react-app/jest" 22 | ] 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | ">0.2%", 27 | "not dead", 28 | "not op_mini all" 29 | ], 30 | "development": [ 31 | "last 1 chrome version", 32 | "last 1 firefox version", 33 | "last 1 safari version" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/react_pagination/6595bd0fe70b5935644891add14d992119494675/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/react_pagination/6595bd0fe70b5935644891add14d992119494675/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/react_pagination/6595bd0fe70b5935644891add14d992119494675/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import Example1 from "./Example1"; 2 | import Example2 from "./Example2"; 3 | 4 | function App() { 5 | 6 | return 7 | } 8 | 9 | export default App; 10 | -------------------------------------------------------------------------------- /src/Example1.js: -------------------------------------------------------------------------------- 1 | import { getPostsPage } from './api/axios' 2 | import { useState, useEffect } from 'react' 3 | import Post from './Post' 4 | 5 | const Example1 = () => { 6 | const [page, setPage] = useState(1) 7 | const [posts, setPosts] = useState([]) 8 | 9 | useEffect(() => { 10 | 11 | getPostsPage(page).then(json => setPosts(json)) 12 | 13 | }, [page]) 14 | 15 | const content = posts.map(post => ) 16 | 17 | const nextPage = () => setPage(prev => prev + 1) 18 | 19 | const prevPage = () => setPage(prev => prev - 1) 20 | 21 | return ( 22 | <> 23 | 27 | {content} 28 | 29 | ) 30 | } 31 | export default Example1 -------------------------------------------------------------------------------- /src/Example2.js: -------------------------------------------------------------------------------- 1 | import { useQuery } from 'react-query' 2 | import { getUsersPage } from './api/axios' 3 | import { useState } from 'react' 4 | import User from './User' 5 | import PageButton from './PageButton' 6 | 7 | const Example2 = () => { 8 | const [page, setPage] = useState(1) 9 | 10 | const { 11 | isLoading, 12 | isError, 13 | error, 14 | data: users, 15 | isFetching, 16 | isPreviousData, 17 | } = useQuery(['/users', page], () => getUsersPage(page), { 18 | keepPreviousData: true 19 | }) 20 | 21 | if (isLoading) return

Loading Users...

22 | 23 | if (isError) return

Error: {error.message}

24 | 25 | const content = users.data.map(user => ) 26 | 27 | const lastPage = () => setPage(users.total_pages) 28 | 29 | const firstPage = () => setPage(1) 30 | 31 | const pagesArray = Array(users.total_pages).fill().map((_, index) => index + 1) 32 | 33 | const nav = ( 34 | 40 | ) 41 | 42 | return ( 43 | <> 44 | {nav} 45 | {isFetching && Loading...} 46 | {content} 47 | 48 | ) 49 | } 50 | export default Example2 -------------------------------------------------------------------------------- /src/PageButton.js: -------------------------------------------------------------------------------- 1 | const PageButton = ({ pg, setPage }) => { 2 | return 3 | } 4 | 5 | export default PageButton -------------------------------------------------------------------------------- /src/Post.js: -------------------------------------------------------------------------------- 1 | const Post = ({ post }) => { 2 | return ( 3 |
4 |

{post.title}

5 |

{post.body}

6 |

Post ID: {post.id}

7 |
8 | ) 9 | } 10 | export default Post -------------------------------------------------------------------------------- /src/User.js: -------------------------------------------------------------------------------- 1 | const User = ({ user }) => { 2 | return ( 3 |
4 | {`${user.first_name} 5 |

{`${user.first_name} ${user.last_name}`}

6 |

Email: {user.email}

7 |

User ID: {user.id}

8 |
9 | ) 10 | } 11 | export default User -------------------------------------------------------------------------------- /src/api/axios.js: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | 3 | export const axiosOne = axios.create({ 4 | baseURL: 'https://jsonplaceholder.typicode.com' 5 | }) 6 | 7 | export const getPostsPage = async (pageParam = 1) => { 8 | const response = await axiosOne.get(`/posts?_page=${pageParam}`) 9 | return response.data 10 | } 11 | 12 | export const axiosTwo = axios.create({ 13 | baseURL: 'https://reqres.in/api' 14 | }) 15 | 16 | export const getUsersPage = async (pageParam = 1) => { 17 | const response = await axiosTwo.get(`/users?page=${pageParam}`) 18 | return response.data 19 | } 20 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Nunito&display=swap"); 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | html { 10 | font-size: 1.5rem; 11 | } 12 | 13 | body { 14 | background-color: #000; 15 | font-family: 'Nunito', sans-serif; 16 | } 17 | 18 | nav { 19 | display: flex; 20 | flex-flow: row nowrap; 21 | justify-content: space-between; 22 | align-items: center; 23 | } 24 | 25 | button { 26 | margin: 1em; 27 | padding: 1em; 28 | font: inherit; 29 | border-radius: 15px; 30 | } 31 | 32 | p { 33 | color: whitesmoke; 34 | } 35 | 36 | article { 37 | margin: 1em; 38 | padding: 1em; 39 | background-color: midnightblue; 40 | color: whitesmoke; 41 | border-radius: 15px; 42 | } 43 | 44 | h2::first-letter, 45 | p::first-letter { 46 | text-transform: uppercase; 47 | } 48 | 49 | img { 50 | border-radius: 15px; 51 | display: block; 52 | } 53 | 54 | .nav-ex2 { 55 | margin-top: 1rem; 56 | justify-content: center; 57 | } 58 | 59 | .nav-ex2 button { 60 | width: 85px; 61 | height: auto; 62 | margin: 0; 63 | border: none; 64 | border-right: 1px solid #000; 65 | border-radius: 0; 66 | } 67 | 68 | .nav-ex2 button:focus { 69 | background-color: yellow; 70 | } 71 | 72 | .loading { 73 | position: absolute; 74 | top: 1rem; 75 | left: 1rem; 76 | color: #fff; 77 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | import { QueryClient, QueryClientProvider, } from 'react-query' 7 | 8 | const queryClient = new QueryClient() 9 | 10 | const root = ReactDOM.createRoot(document.getElementById('root')); 11 | root.render( 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | --------------------------------------------------------------------------------