Skip to content

Commit a6bb549

Browse files
committed
updated
1 parent 86f0b7a commit a6bb549

File tree

10 files changed

+233
-90
lines changed

10 files changed

+233
-90
lines changed

.vscode/settings.json

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"typescript.tsdk": "node_modules\\typescript\\lib",
3+
"typescript.enablePromptUseWorkspaceTsdk": true
4+
}

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@reduxjs/toolkit": "^1.9.3",
1213
"@types/node": "18.15.3",
1314
"@types/react": "18.0.28",
1415
"@types/react-dom": "18.0.11",
@@ -17,6 +18,7 @@
1718
"next": "13.2.4",
1819
"react": "18.2.0",
1920
"react-dom": "18.2.0",
21+
"react-redux": "^8.0.5",
2022
"typescript": "5.0.2"
2123
}
2224
}

src/app/layout.tsx

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
1-
import './globals.css'
1+
// import "./globals.css";
2+
import { Providers } from "@/redux/provider";
23

34
export const metadata = {
4-
title: 'Create Next App',
5-
description: 'Generated by create next app',
6-
}
5+
title: "Create Next App",
6+
description: "Generated by create next app",
7+
};
78

89
export default function RootLayout({
910
children,
1011
}: {
11-
children: React.ReactNode
12+
children: React.ReactNode;
1213
}) {
1314
return (
1415
<html lang="en">
15-
<body>{children}</body>
16+
<body>
17+
<Providers>{children}</Providers>
18+
</body>
1619
</html>
17-
)
20+
);
1821
}

src/app/page.tsx

+46-81
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,56 @@
1-
import Image from 'next/image'
2-
import { Inter } from 'next/font/google'
3-
import styles from './page.module.css'
1+
"use client";
42

5-
const inter = Inter({ subsets: ['latin'] })
3+
import { useGetUsersQuery } from "@/redux/api/userApi";
4+
import { decrement, increment, reset } from "@/redux/features/counter";
5+
import { useAppDispatch, useAppSelector } from "@/redux/hooks";
66

77
export default function Home() {
8-
return (
9-
<main className={styles.main}>
10-
<div className={styles.description}>
11-
<p>
12-
Get started by editing&nbsp;
13-
<code className={styles.code}>src/app/page.tsx</code>
14-
</p>
15-
<div>
16-
<a
17-
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
18-
target="_blank"
19-
rel="noopener noreferrer"
20-
>
21-
By{' '}
22-
<Image
23-
src="/vercel.svg"
24-
alt="Vercel Logo"
25-
className={styles.vercelLogo}
26-
width={100}
27-
height={24}
28-
priority
29-
/>
30-
</a>
31-
</div>
32-
</div>
8+
const count = useAppSelector((state) => state.counterReducer.value);
9+
const dispatch = useAppDispatch();
3310

34-
<div className={styles.center}>
35-
<Image
36-
className={styles.logo}
37-
src="/next.svg"
38-
alt="Next.js Logo"
39-
width={180}
40-
height={37}
41-
priority
42-
/>
43-
<div className={styles.thirteen}>
44-
<Image src="/thirteen.svg" alt="13" width={40} height={31} priority />
45-
</div>
46-
</div>
11+
const { isLoading, isFetching, data, error } = useGetUsersQuery(null);
4712

48-
<div className={styles.grid}>
49-
<a
50-
href="https://beta.nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
51-
className={styles.card}
52-
target="_blank"
53-
rel="noopener noreferrer"
54-
>
55-
<h2 className={inter.className}>
56-
Docs <span>-&gt;</span>
57-
</h2>
58-
<p className={inter.className}>
59-
Find in-depth information about Next.js features and API.
60-
</p>
61-
</a>
62-
63-
<a
64-
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
65-
className={styles.card}
66-
target="_blank"
67-
rel="noopener noreferrer"
13+
return (
14+
<main style={{ maxWidth: 1200, marginInline: "auto", padding: 20 }}>
15+
<div style={{ marginBottom: "4rem", textAlign: "center" }}>
16+
<h4 style={{ marginBottom: 16 }}>{count}</h4>
17+
<button onClick={() => dispatch(increment())}>increment</button>
18+
<button
19+
onClick={() => dispatch(decrement())}
20+
style={{ marginInline: 16 }}
6821
>
69-
<h2 className={inter.className}>
70-
Templates <span>-&gt;</span>
71-
</h2>
72-
<p className={inter.className}>Explore the Next.js 13 playground.</p>
73-
</a>
22+
decrement
23+
</button>
24+
<button onClick={() => dispatch(reset())}>reset</button>
25+
</div>
7426

75-
<a
76-
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
77-
className={styles.card}
78-
target="_blank"
79-
rel="noopener noreferrer"
27+
{error ? (
28+
<p>Oh no, there was an error</p>
29+
) : isLoading || isFetching ? (
30+
<p>Loading...</p>
31+
) : data ? (
32+
<div
33+
style={{
34+
display: "grid",
35+
gridTemplateColumns: "1fr 1fr 1fr 1fr",
36+
gap: 20,
37+
}}
8038
>
81-
<h2 className={inter.className}>
82-
Deploy <span>-&gt;</span>
83-
</h2>
84-
<p className={inter.className}>
85-
Instantly deploy your Next.js site to a shareable URL with Vercel.
86-
</p>
87-
</a>
88-
</div>
39+
{data.map((user) => (
40+
<div
41+
key={user.id}
42+
style={{ border: "1px solid #ccc", textAlign: "center" }}
43+
>
44+
<img
45+
src={`https://robohash.org/${user.id}?set=set2&size=180x180`}
46+
alt={user.name}
47+
style={{ height: 180, width: 180 }}
48+
/>
49+
<h3>{user.name}</h3>
50+
</div>
51+
))}
52+
</div>
53+
) : null}
8954
</main>
90-
)
55+
);
9156
}

src/redux/api/userApi.ts

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2+
3+
type User = {
4+
id: number;
5+
name: string;
6+
email: number;
7+
};
8+
9+
export const userApi = createApi({
10+
reducerPath: "userApi",
11+
refetchOnFocus: true,
12+
baseQuery: fetchBaseQuery({
13+
baseUrl: "https://jsonplaceholder.typicode.com/",
14+
}),
15+
endpoints: (builder) => ({
16+
getUsers: builder.query<User[], null>({
17+
query: () => "users",
18+
}),
19+
getUserById: builder.query<User, { id: string }>({
20+
query: ({ id }) => `users/${id}`,
21+
}),
22+
}),
23+
});
24+
25+
export const { useGetUsersQuery, useGetUserByIdQuery } = userApi;

src/redux/features/counter.ts

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
2+
3+
type CounterState = {
4+
value: number;
5+
};
6+
7+
const initialState = {
8+
value: 0,
9+
} as CounterState;
10+
11+
export const counter = createSlice({
12+
name: "counter",
13+
initialState,
14+
reducers: {
15+
reset: () => initialState,
16+
increment: (state) => {
17+
state.value += 1;
18+
},
19+
decrement: (state) => {
20+
state.value -= 1;
21+
},
22+
incrementByAmount: (state, action: PayloadAction<number>) => {
23+
state.value += action.payload;
24+
},
25+
decrementByAmount: (state, action: PayloadAction<number>) => {
26+
state.value -= action.payload;
27+
},
28+
},
29+
});
30+
31+
export const {
32+
increment,
33+
incrementByAmount,
34+
decrement,
35+
decrementByAmount,
36+
reset,
37+
} = counter.actions;
38+
export default counter.reducer;

src/redux/hooks.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
2+
import type { RootState, AppDispatch } from "./store";
3+
4+
export const useAppDispatch = () => useDispatch<AppDispatch>();
5+
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

src/redux/provider.tsx

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
"use client";
2+
3+
import { store } from "./store";
4+
import { Provider } from "react-redux";
5+
6+
export function Providers({ children }: { children: React.ReactNode }) {
7+
return <Provider store={store}>{children}</Provider>;
8+
}

src/redux/store.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { configureStore } from "@reduxjs/toolkit";
2+
import counterReducer from "./features/counter";
3+
import { userApi } from "./api/userApi";
4+
import { setupListeners } from "@reduxjs/toolkit/dist/query";
5+
6+
export const store = configureStore({
7+
reducer: {
8+
counterReducer,
9+
[userApi.reducerPath]: userApi.reducer,
10+
},
11+
devTools: process.env.NODE_ENV !== "production",
12+
middleware: (getDefaultMiddleware) =>
13+
getDefaultMiddleware({}).concat([userApi.middleware]),
14+
});
15+
16+
setupListeners(store.dispatch);
17+
18+
export type RootState = ReturnType<typeof store.getState>;
19+
export type AppDispatch = typeof store.dispatch;

0 commit comments

Comments
 (0)