diff --git a/package.json b/package.json index 2643cfd..c096670 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "start": "PORT=3001 react-scripts start", "build": "react-scripts build", "test": "react-scripts test", + "server":"json-server --watch ./src/api/db.json --port 5000", "lint": "eslint . --ext .js --fix", "eject": "react-scripts eject", "prepare": "husky install", diff --git a/src/api/db.json b/src/api/db.json new file mode 100644 index 0000000..57e2e50 --- /dev/null +++ b/src/api/db.json @@ -0,0 +1,368 @@ +{ + "posts": [ + { + "userId": 1, + "id": 1, + "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" + }, + { + "userId": 1, + "id": 2, + "title": "qui est esse", + "body": "est rerum tempore vitae\nsequi sint nihil reprehenderit dolor beatae ea dolores neque\nfugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis\nqui aperiam non debitis possimus qui neque nisi nulla" + }, + { + "userId": 1, + "id": 3, + "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut", + "body": "et iusto sed quo iure\nvoluptatem occaecati omnis eligendi aut ad\nvoluptatem doloribus vel accusantium quis pariatur\nmolestiae porro eius odio et labore et velit aut" + }, + { + "userId": 1, + "id": 4, + "title": "eum et est occaecati", + "body": "ullam et saepe reiciendis voluptatem adipisci\nsit amet autem assumenda provident rerum culpa\nquis hic commodi nesciunt rem tenetur doloremque ipsam iure\nquis sunt voluptatem rerum illo velit" + }, + { + "userId": 1, + "id": 5, + "title": "nesciunt quas odio", + "body": "repudiandae veniam quaerat sunt sed\nalias aut fugiat sit autem sed est\nvoluptatem omnis possimus esse voluptatibus quis\nest aut tenetur dolor neque" + }, + { + "title": "asdfasdf", + "body": "asdfasdf", + "userId": 1, + "id": 1672861854320 + }, + { + "title": "New Post", + "body": "NEWWWW", + "userId": 1, + "id": 1672862111056 + }, + { + "title": "aaaa", + "body": "aaa", + "userId": 1, + "id": 1672862146765 + }, + { + "title": "asdfasdf", + "body": "asdfasdf", + "userId": 1, + "id": 1672862165463 + }, + { + "title": "bbbbbbb", + "body": "bbbbbbbb", + "userId": 1, + "id": 1672862185382 + }, + { + "title": "cccc", + "body": "cccc", + "userId": 1, + "id": 1672862529960 + }, + { + "title": "ddddd", + "body": "dddd", + "userId": 1, + "id": 1672862596875 + }, + { + "title": "asdfasdf", + "body": "asdfasdf", + "userId": 1, + "id": 1672862658361 + }, + { + "title": "asdfasdfasdf", + "body": "asdfasdfasdf", + "userId": 1, + "id": 1672862767036 + }, + { + "title": "bfdbdfbdfbdfb", + "body": "dfbdfbdfbdf", + "userId": 1, + "id": 1672862857378 + }, + { + "title": "bfdbdfbdfbdfb", + "body": "dfbdfbdfbdf", + "userId": 1, + "id": 1672862869742 + }, + { + "title": "bfdbdfbdfbdfb", + "body": "dfbdfbdfbdf", + "userId": 1, + "id": 1672862928919 + }, + { + "title": "123", + "body": "123123", + "userId": 1, + "id": 1696404766131 + }, + { + "title": "333", + "body": "3333", + "userId": 1, + "id": 1696404788523 + }, + { + "title": "33", + "body": "222", + "userId": 1, + "id": 1696404832426 + }, + { + "title": "taitt", + "body": "tat", + "userId": 1, + "id": 1696404931850 + }, + { + "title": "32", + "body": "233", + "userId": 1, + "id": 1696406110656 + } + ], + "users": [ + { + "id": 1, + "name": "Leanne Graham", + "username": "Bret", + "email": "Sincere@april.biz", + "address": { + "street": "Kulas Light", + "suite": "Apt. 556", + "city": "Gwenborough", + "zipcode": "92998-3874", + "geo": { + "lat": "-37.3159", + "lng": "81.1496" + } + }, + "phone": "1-770-736-8031 x56442", + "website": "hildegard.org", + "company": { + "name": "Romaguera-Crona", + "catchPhrase": "Multi-layered client-server neural-net", + "bs": "harness real-time e-markets" + } + }, + { + "id": 2, + "name": "Ervin Howell", + "username": "Antonette", + "email": "Shanna@melissa.tv", + "address": { + "street": "Victor Plains", + "suite": "Suite 879", + "city": "Wisokyburgh", + "zipcode": "90566-7771", + "geo": { + "lat": "-43.9509", + "lng": "-34.4618" + } + }, + "phone": "010-692-6593 x09125", + "website": "anastasia.net", + "company": { + "name": "Deckow-Crist", + "catchPhrase": "Proactive didactic contingency", + "bs": "synergize scalable supply-chains" + } + }, + { + "id": 3, + "name": "Clementine Bauch", + "username": "Samantha", + "email": "Nathan@yesenia.net", + "address": { + "street": "Douglas Extension", + "suite": "Suite 847", + "city": "McKenziehaven", + "zipcode": "59590-4157", + "geo": { + "lat": "-68.6102", + "lng": "-47.0653" + } + }, + "phone": "1-463-123-4447", + "website": "ramiro.info", + "company": { + "name": "Romaguera-Jacobson", + "catchPhrase": "Face to face bifurcated interface", + "bs": "e-enable strategic applications" + } + }, + { + "id": 4, + "name": "Patricia Lebsack", + "username": "Karianne", + "email": "Julianne.OConner@kory.org", + "address": { + "street": "Hoeger Mall", + "suite": "Apt. 692", + "city": "South Elvis", + "zipcode": "53919-4257", + "geo": { + "lat": "29.4572", + "lng": "-164.2990" + } + }, + "phone": "493-170-9623 x156", + "website": "kale.biz", + "company": { + "name": "Robel-Corkery", + "catchPhrase": "Multi-tiered zero tolerance productivity", + "bs": "transition cutting-edge web services" + } + }, + { + "id": 5, + "name": "Chelsey Dietrich", + "username": "Kamren", + "email": "Lucio_Hettinger@annie.ca", + "address": { + "street": "Skiles Walks", + "suite": "Suite 351", + "city": "Roscoeview", + "zipcode": "33263", + "geo": { + "lat": "-31.8129", + "lng": "62.5342" + } + }, + "phone": "(254)954-1289", + "website": "demarco.info", + "company": { + "name": "Keebler LLC", + "catchPhrase": "User-centric fault-tolerant solution", + "bs": "revolutionize end-to-end systems" + } + }, + { + "id": 6, + "name": "Mrs. Dennis Schulist", + "username": "Leopoldo_Corkery", + "email": "Karley_Dach@jasper.info", + "address": { + "street": "Norberto Crossing", + "suite": "Apt. 950", + "city": "South Christy", + "zipcode": "23505-1337", + "geo": { + "lat": "-71.4197", + "lng": "71.7478" + } + }, + "phone": "1-477-935-8478 x6430", + "website": "ola.org", + "company": { + "name": "Considine-Lockman", + "catchPhrase": "Synchronised bottom-line interface", + "bs": "e-enable innovative applications" + } + }, + { + "id": 7, + "name": "Kurtis Weissnat", + "username": "Elwyn.Skiles", + "email": "Telly.Hoeger@billy.biz", + "address": { + "street": "Rex Trail", + "suite": "Suite 280", + "city": "Howemouth", + "zipcode": "58804-1099", + "geo": { + "lat": "24.8918", + "lng": "21.8984" + } + }, + "phone": "210.067.6132", + "website": "elvis.io", + "company": { + "name": "Johns Group", + "catchPhrase": "Configurable multimedia task-force", + "bs": "generate enterprise e-tailers" + } + }, + { + "id": 8, + "name": "Nicholas Runolfsdottir V", + "username": "Maxime_Nienow", + "email": "Sherwood@rosamond.me", + "address": { + "street": "Ellsworth Summit", + "suite": "Suite 729", + "city": "Aliyaview", + "zipcode": "45169", + "geo": { + "lat": "-14.3990", + "lng": "-120.7677" + } + }, + "phone": "586.493.6943 x140", + "website": "jacynthe.com", + "company": { + "name": "Abernathy Group", + "catchPhrase": "Implemented secondary concept", + "bs": "e-enable extensible e-tailers" + } + }, + { + "id": 9, + "name": "Glenna Reichert", + "username": "Delphine", + "email": "Chaim_McDermott@dana.io", + "address": { + "street": "Dayna Park", + "suite": "Suite 449", + "city": "Bartholomebury", + "zipcode": "76495-3109", + "geo": { + "lat": "24.6463", + "lng": "-168.8889" + } + }, + "phone": "(775)976-6794 x41206", + "website": "conrad.com", + "company": { + "name": "Yost and Sons", + "catchPhrase": "Switchable contextually-based project", + "bs": "aggregate real-time technologies" + } + }, + { + "id": 10, + "name": "Clementina DuBuque", + "username": "Moriah.Stanton", + "email": "Rey.Padberg@karina.biz", + "address": { + "street": "Kattie Turnpike", + "suite": "Suite 198", + "city": "Lebsackbury", + "zipcode": "31428-2261", + "geo": { + "lat": "-38.2386", + "lng": "57.2232" + } + }, + "phone": "024-648-3804", + "website": "ambrose.net", + "company": { + "name": "Hoeger LLC", + "catchPhrase": "Centralized empowering task-force", + "bs": "target end-to-end models" + } + } + ] +} \ No newline at end of file diff --git a/src/libs/React-Query/index.js b/src/libs/React-Query/index.js index 2448486..4a255de 100644 --- a/src/libs/React-Query/index.js +++ b/src/libs/React-Query/index.js @@ -1,30 +1,11 @@ -import React from 'react'; -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; -import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; -import Learn_1 from './learn_1'; -import axios from 'axios'; - -export const BASE_URL = 'https://dummyjson.com'; - -// Access the client -const queryClient = new QueryClient({ - defaultOptions: { - queries: { - queryFn: async ({ queryKey }) => { - const res = await axios.get(`${BASE_URL}${queryKey}`); - return res.data; - }, - }, - }, -}); +// import Learn_1 from './learn_1'; +import Learn_2 from './learn_2'; const React_Query = () => { return ( <> - - - - + {/* */} + ); }; diff --git a/src/libs/React-Query/learn_1/index.js b/src/libs/React-Query/learn_1/index.js index cc4c1c8..ccc71f8 100644 --- a/src/libs/React-Query/learn_1/index.js +++ b/src/libs/React-Query/learn_1/index.js @@ -1,12 +1,31 @@ import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import axios from 'axios'; import Posts from './pages/Posts'; -const Learn_1 = () => { +export const BASE_URL = 'https://dummyjson.com'; + +const index = () => { + // Access the client + const queryClient = new QueryClient({ + defaultOptions: { + queries: { + queryFn: async ({ queryKey }) => { + const res = await axios.get(`${BASE_URL}${queryKey}`); + return res.data; + }, + }, + }, + }); return ( <> - + + + + ); }; -export default Learn_1; +export default index; diff --git a/src/libs/React-Query/learn_1/mutation/Mutation.js b/src/libs/React-Query/learn_1/mutation/Mutation.js index 6ab049d..1450906 100644 --- a/src/libs/React-Query/learn_1/mutation/Mutation.js +++ b/src/libs/React-Query/learn_1/mutation/Mutation.js @@ -1,7 +1,7 @@ import React from 'react'; import axios from 'axios'; import { useMutation } from '@tanstack/react-query'; -import { BASE_URL } from '../..'; +import { BASE_URL } from '..'; const MutationPage = () => { const createUser = async (userData) => { diff --git a/src/libs/React-Query/learn_1/pages/Posts.js b/src/libs/React-Query/learn_1/pages/Posts.js index 34f5fb6..a1f0135 100644 --- a/src/libs/React-Query/learn_1/pages/Posts.js +++ b/src/libs/React-Query/learn_1/pages/Posts.js @@ -1,5 +1,5 @@ -import React from 'react'; import { useQuery } from '@tanstack/react-query'; +import React from 'react'; import MutationPage from '../mutation/Mutation'; const Posts = () => { @@ -24,6 +24,7 @@ const Posts = () => { return ( <> +

diff --git a/src/libs/React-Query/learn_2/Learn_2.js b/src/libs/React-Query/learn_2/Learn_2.js new file mode 100644 index 0000000..c0a4141 --- /dev/null +++ b/src/libs/React-Query/learn_2/Learn_2.js @@ -0,0 +1,38 @@ +import React, { useState } from 'react'; +import PostsList1 from './pages/PostsList1'; +import { useQueryClient } from '@tanstack/react-query'; +import PostsList2 from './pages/PostsList2'; +import Post from './pages/Post'; +import { getPost } from './api/posts'; +import { CreatePost } from './pages/CreatePost'; + +const Learn_2 = () => { + const [currentPage, setCurrentPage] = useState(); + const queryClient = useQueryClient(); + + function onHoverPostOneLink() { + queryClient.prefetchQuery({ + queryKey: ['posts', 1], + queryFn: () => getPost(1), + }); + } + + return ( + <> +
+ + + +
+ {currentPage} + +
+ + ); +}; + +export default Learn_2; diff --git a/src/libs/React-Query/learn_2/api/posts.js b/src/libs/React-Query/learn_2/api/posts.js new file mode 100644 index 0000000..862abc6 --- /dev/null +++ b/src/libs/React-Query/learn_2/api/posts.js @@ -0,0 +1,32 @@ +import axios from 'axios'; + +export async function getPosts() { + const res = await axios.get('http://localhost:5000/posts', { params: { _sort: 'title' } }); + return res.data; +} + +export async function getPostsPaginated(page) { + const res = await axios.get('http://localhost:5000/posts', { + params: { _page: page, _sort: 'title', _limit: 2 }, + }); + const hasNext = page * 2 <= parseInt(res.headers['x-total-count']); + return { + nextPage: hasNext ? page + 1 : undefined, + previousPage: page > 1 ? page - 1 : undefined, + posts: res.data, + }; +} + +export function getPost(id, hi) { + return axios.get(`http://localhost:5000/posts/${id}`).then((res) => res.data); +} + +export async function createPost({ title, body }) { + const res = await axios.post('http://localhost:5000/posts', { + title, + body, + userId: 1, + id: Date.now(), + }); + return res.data; +} diff --git a/src/libs/React-Query/learn_2/api/users.js b/src/libs/React-Query/learn_2/api/users.js new file mode 100644 index 0000000..2a8b60b --- /dev/null +++ b/src/libs/React-Query/learn_2/api/users.js @@ -0,0 +1,5 @@ +import axios from 'axios'; + +export function getUser(id) { + return axios.get(`http://localhost:5000/users/${id}`).then((res) => res.data); +} diff --git a/src/libs/React-Query/learn_2/index.js b/src/libs/React-Query/learn_2/index.js new file mode 100644 index 0000000..e800c0f --- /dev/null +++ b/src/libs/React-Query/learn_2/index.js @@ -0,0 +1,20 @@ +import React from 'react'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import Learn_2 from './Learn_2'; + +const index = () => { + const queryClient = new QueryClient({ + defaultOptions: { queries: { staleTime: 1000 * 60 * 5 } }, + }); + return ( + <> + + + + + + ); +}; + +export default index; diff --git a/src/libs/React-Query/learn_2/pages/CreatePost.js b/src/libs/React-Query/learn_2/pages/CreatePost.js new file mode 100644 index 0000000..5907eed --- /dev/null +++ b/src/libs/React-Query/learn_2/pages/CreatePost.js @@ -0,0 +1,46 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useRef } from 'react'; +import { createPost } from '../api/posts'; +import Post from './Post'; + +export function CreatePost({ setCurrentPage }) { + const titleRef = useRef(); + const bodyRef = useRef(); + const queryClient = useQueryClient(); + const createPostMutation = useMutation({ + mutationFn: createPost, + onSuccess: (data) => { + queryClient.setQueryData(['posts', data.id], data); + queryClient.invalidateQueries(['posts'], { exact: true }); + setCurrentPage(); + }, + }); + + function handleSubmit(e) { + e.preventDefault(); + createPostMutation.mutate({ + title: titleRef.current.value, + body: bodyRef.current.value, + }); + } + + return ( +
+ {createPostMutation.isError && JSON.stringify(createPostMutation.error)} +

Create Post

+
+
+ + +
+
+ + +
+ +
+
+ ); +} diff --git a/src/libs/React-Query/learn_2/pages/Post.js b/src/libs/React-Query/learn_2/pages/Post.js new file mode 100644 index 0000000..5b1b8a9 --- /dev/null +++ b/src/libs/React-Query/learn_2/pages/Post.js @@ -0,0 +1,37 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPost } from '../api/posts'; +import { getUser } from '../api/users'; + +export default function Post({ id }) { + const postQuery = useQuery({ + queryKey: ['posts', id], + queryFn: () => getPost(id), + }); + + const userQuery = useQuery({ + queryKey: ['users', postQuery?.data?.userId], + enabled: postQuery?.data?.userId != null, + queryFn: () => getUser(postQuery.data.userId), + }); + + if (postQuery.status === 'loading') return

Loading...

; + if (postQuery.status === 'error') { + return

{JSON.stringify(postQuery.error)}

; + } + + return ( + <> +

+ {postQuery.data.title}
+ + {userQuery.isLoading + ? 'Loading User...' + : userQuery.isError + ? 'Error Loading User' + : userQuery.data.name} + +

+

{postQuery.data.body}

+ + ); +} diff --git a/src/libs/React-Query/learn_2/pages/PostsList1.js b/src/libs/React-Query/learn_2/pages/PostsList1.js new file mode 100644 index 0000000..bfdb090 --- /dev/null +++ b/src/libs/React-Query/learn_2/pages/PostsList1.js @@ -0,0 +1,26 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPosts } from '../api/posts'; + +export default function PostsList1() { + const postsQuery = useQuery({ + queryKey: ['posts'], + queryFn: getPosts, + placeholderData: [{ id: 1, title: 'Initial Data' }], + }); + + if (postsQuery.status === 'loading') return

Loading...

; + if (postsQuery.status === 'error') { + return

{JSON.stringify(postsQuery.error)}

; + } + + return ( +
+

Posts List 1

+
    + {postsQuery.data.map((post) => ( +
  1. {post.title}
  2. + ))} +
+
+ ); +} diff --git a/src/libs/React-Query/learn_2/pages/PostsList2.js b/src/libs/React-Query/learn_2/pages/PostsList2.js new file mode 100644 index 0000000..a629a3b --- /dev/null +++ b/src/libs/React-Query/learn_2/pages/PostsList2.js @@ -0,0 +1,25 @@ +import { useQuery } from '@tanstack/react-query'; +import { getPosts } from '../api/posts'; + +export default function PostsList2() { + const postsQuery = useQuery({ + queryKey: ['posts'], + queryFn: getPosts, + }); + + if (postsQuery.status === 'loading') return

Loading...

; + if (postsQuery.status === 'error') { + return

{JSON.stringify(postsQuery.error)}

; + } + + return ( +
+

Post List 2

+
    + {postsQuery.data.map((post) => ( +
  1. {post.title}
  2. + ))} +
+
+ ); +}