├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
└── vite.svg
├── src
├── App.css
├── App.jsx
├── assets
│ └── react.svg
├── components
│ ├── AddUserForm.jsx
│ └── UserLists.jsx
├── index.css
├── main.jsx
├── req-processor
│ └── requestProcessor.js
└── utils
│ └── axios.js
├── tailwind.config.js
└── vite.config.js
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: { browser: true, es2020: true },
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:react/recommended',
7 | 'plugin:react/jsx-runtime',
8 | 'plugin:react-hooks/recommended',
9 | ],
10 | ignorePatterns: ['dist', '.eslintrc.cjs'],
11 | parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
12 | settings: { react: { version: '18.2' } },
13 | plugins: ['react-refresh'],
14 | rules: {
15 | 'react-refresh/only-export-components': [
16 | 'warn',
17 | { allowConstantExport: true },
18 | ],
19 | },
20 | }
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-query-demo",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "axios": "^1.5.1",
14 | "react": "^18.2.0",
15 | "react-dom": "^18.2.0",
16 | "react-query": "^3.39.3"
17 | },
18 | "devDependencies": {
19 | "@types/react": "^18.2.15",
20 | "@types/react-dom": "^18.2.7",
21 | "@vitejs/plugin-react": "^4.0.3",
22 | "autoprefixer": "^10.4.16",
23 | "eslint": "^8.45.0",
24 | "eslint-plugin-react": "^7.32.2",
25 | "eslint-plugin-react-hooks": "^4.6.0",
26 | "eslint-plugin-react-refresh": "^0.4.3",
27 | "postcss": "^8.4.31",
28 | "tailwindcss": "^3.3.3",
29 | "vite": "^4.4.5"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | /* Reset some default styles */
2 | html,
3 | body,
4 | div,
5 | h1,
6 | h2,
7 | h3,
8 | p,
9 | ul,
10 | li,
11 | button {
12 | margin: 0;
13 | padding: 0;
14 | box-sizing: border-box;
15 | }
16 |
17 | /* Set up a background color and font */
18 | body {
19 | font-family: Arial, sans-serif;
20 | background-color: #f7fafc;
21 | }
22 |
23 | /* Container for the entire app */
24 | .container {
25 | max-width: 800px;
26 | margin: 0 auto;
27 | padding: 20px;
28 | }
29 |
30 | /* Header styles */
31 | h1 {
32 | font-size: 2rem;
33 | font-weight: 700;
34 | margin-bottom: 20px;
35 | }
36 |
37 | /* Item card styles */
38 | .item-card {
39 | border: 1px solid #e2e8f0;
40 | border-radius: 0.5rem;
41 | padding: 1rem;
42 | margin: 0.5rem;
43 | background-color: #fff;
44 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
45 | }
46 |
47 | .item-card h3 {
48 | font-size: 1.5rem;
49 | font-weight: 600;
50 | margin-bottom: 0.5rem;
51 | }
52 |
53 | .item-card p {
54 | font-size: 1rem;
55 | color: #4a5568;
56 | }
57 |
58 | /* Button styles */
59 | .button {
60 | display: inline-block;
61 | padding: 0.5rem 1rem;
62 | border: none;
63 | border-radius: 0.25rem;
64 | cursor: pointer;
65 | transition: background-color 0.2s;
66 | }
67 |
68 | .button-primary {
69 | background-color: #4c51bf;
70 | color: #ffffff;
71 | }
72 |
73 | .button-primary:hover {
74 | background-color: #4338ca;
75 | }
76 |
77 | .button-danger {
78 | background-color: #e53e3e;
79 | color: #ffffff;
80 | }
81 |
82 | .button-danger:hover {
83 | background-color: #c53030;
84 | }
85 |
86 | /* Form styles */
87 | .form {
88 | background-color: #ffffff;
89 | border: 1px solid #e2e8f0;
90 | border-radius: 0.5rem;
91 | padding: 1rem;
92 | margin: 1rem 0;
93 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
94 | }
95 |
96 | .form h2 {
97 | font-size: 1.5rem;
98 | font-weight: 600;
99 | margin-bottom: 1rem;
100 | }
101 |
102 | .form input[type="text"] {
103 | width: 100%;
104 | padding: 0.5rem;
105 | border: 1px solid #cbd5e0;
106 | border-radius: 0.25rem;
107 | font-size: 1rem;
108 | margin-bottom: 1rem;
109 | }
110 |
111 | /* Create button styles */
112 | .create-button {
113 | background-color: #48bb78;
114 | color: #ffffff;
115 | }
116 |
117 | .create-button:hover {
118 | background-color: #38a169;
119 | }
120 |
121 | /* Update button styles */
122 | .update-button {
123 | background-color: #4299e1;
124 | color: #ffffff;
125 | }
126 |
127 | .update-button:hover {
128 | background-color: #3182ce;
129 | }
130 |
--------------------------------------------------------------------------------
/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { QueryClient, QueryClientProvider } from "react-query";
2 | import AddUserForm from "./components/AddUserForm";
3 | import UserLists from "./components/UserLists";
4 |
5 | const queryClient = new QueryClient();
6 |
7 | const App = () => {
8 | return (
9 |
15 | );
16 | };
17 |
18 | export default App;
19 |
--------------------------------------------------------------------------------
/src/assets/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/components/AddUserForm.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useRequestProcessor } from "../req-processor/requestProcessor";
3 | import axiosClient from "../utils/axios";
4 |
5 | function AddUserForm() {
6 | const { mutate } = useRequestProcessor();
7 | const [name, setName] = useState("");
8 |
9 | const handleSubmit = (event) => {
10 | event.preventDefault();
11 |
12 | mutate("addUser", () =>
13 | axiosClient.post("/photos", { name }).then((res) => res.data)
14 | );
15 | setName("");
16 | };
17 |
18 | return (
19 |
30 | );
31 | }
32 |
33 | export default AddUserForm;
34 |
--------------------------------------------------------------------------------
/src/components/UserLists.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { useRequestProcessor } from "../req-processor/requestProcessor";
3 | import axiosClient from "../utils/axios";
4 |
5 | export default function UserLists() {
6 | const { query } = useRequestProcessor();
7 | const {
8 | data: users,
9 | isLoading,
10 | isError,
11 | } = query("users", () => axiosClient.get("/users").then((res) => res.data), {
12 | enabled: true,
13 | });
14 | if (isLoading) return Loading...
;
15 | if (isError) return Error
;
16 | return (
17 |
18 | {users.map((user) => {
19 | return (
20 | -
24 | {user?.name}
25 |
26 | );
27 | })}
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './index.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 |
9 | ,
10 | )
11 |
--------------------------------------------------------------------------------
/src/req-processor/requestProcessor.js:
--------------------------------------------------------------------------------
1 | import { useQuery, useMutation, useQueryClient } from "react-query";
2 |
3 | export function useRequestProcessor() {
4 | const queryClient = useQueryClient();
5 |
6 | function query(key, queryFunction, options = {}) {
7 | return useQuery({
8 | queryKey: key,
9 | queryFn: queryFunction,
10 | ...options,
11 | });
12 | }
13 |
14 | function mutate(key, mutationFunction, options = {}) {
15 | return useMutation({
16 | mutationKey: key,
17 | mutationFn: mutationFunction,
18 | onSettled: () => queryClient.invalidateQueries(key),
19 | ...options,
20 | });
21 | }
22 |
23 | return { query, mutate };
24 | }
25 |
--------------------------------------------------------------------------------
/src/utils/axios.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const axiosClient = axios.create({
4 | baseURL: "https://jsonplaceholder.typicode.com/",
5 | });
6 |
7 | export default axiosClient;
8 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {},
6 | },
7 | plugins: [],
8 | };
9 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------