├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
└── src
├── App.js
├── assets
└── default-image.jpeg
├── data.js
├── index.css
├── index.js
└── tutorial
├── 1-useState
├── final
│ ├── 1-error-example.js
│ ├── 2-useState-basics.js
│ ├── 3-useState-array.js
│ ├── 4-useState-object.js
│ └── 5-useState-counter.js
└── setup
│ ├── 1-error-example.js
│ ├── 2-useState-basics.js
│ ├── 3-useState-array.js
│ ├── 4-useState-object.js
│ └── 5-useState-counter.js
├── 10-prop-types
├── final
│ ├── Product.js
│ ├── index.js
│ └── testing.js
└── setup
│ ├── Product.js
│ └── index.js
├── 11-react-router
├── ReactRouterInfo.md
├── final
│ ├── About.js
│ ├── Error.js
│ ├── Home.js
│ ├── Navbar.js
│ ├── People.js
│ ├── Person.js
│ └── index.js
└── setup
│ ├── About.js
│ ├── Error.js
│ ├── Home.js
│ ├── Navbar.js
│ ├── People.js
│ ├── Person.js
│ └── index.js
├── 12-memo-useMemo-useCallback
├── final
│ └── index.js
└── setup
│ └── index.js
├── 2-useEffect
├── final
│ ├── 1-useEffect-basics.js
│ ├── 2-useEffect-cleanup.js
│ └── 3-useEffect-fetch-data.js
└── setup
│ ├── 1-useEffect-basics.js
│ ├── 2-useEffect-cleanup.js
│ └── 3-useEffect-fetch-data.js
├── 3-conditional-rendering
├── final
│ ├── 1-multiple-returns.js
│ ├── 2-short-circuit.js
│ └── 3-show-hide.js
└── setup
│ ├── 1-multiple-returns.js
│ ├── 2-short-circuit.js
│ └── 3-show-hide.js
├── 4-forms
├── final
│ ├── 1-controlled-inputs.js
│ └── 2-multiple-inputs.js
└── setup
│ ├── 1-controlled-inputs.js
│ └── 2-multiple-inputs.js
├── 5-useRef
├── final
│ └── 1-useRef-basics.js
└── setup
│ └── 1-useRef-basics.js
├── 6-useReducer
├── final
│ ├── Modal.js
│ ├── index.js
│ └── reducer.js
└── setup
│ ├── Modal.js
│ └── index.js
├── 7-prop-drilling
├── final
│ └── 1-prop-drilling.js
└── setup
│ └── 1-prop-drilling.js
├── 8-useContext
├── final
│ └── 1-context-api.js
└── setup
│ └── 1-context-api.js
└── 9-custom-hooks
├── final
├── 1-fetch-example.js
└── 2-useFetch.js
└── setup
├── 1-fetch-example.js
└── 2-useFetch.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 | ## Corresponding Projects
2 |
3 | #### useState
4 |
5 | 1. Birthday Reminder
6 |
7 | #### useEffect and Conditional Rendering
8 |
9 | 2. Tours
10 | 3. Reviews
11 | 4. Accordion
12 | 5. Menu
13 | 6. Tabs
14 | 7. Slider
15 |
16 | #### Forms
17 |
18 | 8. Lorem Ipsum Generator
19 | 9. Color Shades Generator
20 | 10. Grocery Bud
21 |
22 | #### useRef
23 |
24 | 11. Navbar
25 |
26 | #### useContext
27 |
28 | 12. Modal and Sidebar
29 | 13. Stripe Menus
30 |
31 | #### useReducer and useContext
32 |
33 | 14. Cart
34 |
35 | #### React Router
36 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tutorial",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.5.0",
8 | "@testing-library/user-event": "^7.2.1",
9 | "react": "^16.13.1",
10 | "react-dom": "^16.13.1",
11 | "react-router-dom": "^5.2.0",
12 | "react-scripts": "3.4.3"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": {
24 | "production": [
25 | ">0.2%",
26 | "not dead",
27 | "not op_mini all"
28 | ],
29 | "development": [
30 | "last 1 chrome version",
31 | "last 1 firefox version",
32 | "last 1 safari version"
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-advanced-2020/19f34c9a3290feb87b00be0385cd84605ee8e649/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/john-smilga/react-advanced-2020/19f34c9a3290feb87b00be0385cd84605ee8e649/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-advanced-2020/19f34c9a3290feb87b00be0385cd84605ee8e649/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 React from 'react'
2 | function App() {
3 | return (
4 |
5 |
Advanced Tutorial
6 |
7 | )
8 | }
9 |
10 | export default App
11 |
--------------------------------------------------------------------------------
/src/assets/default-image.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/john-smilga/react-advanced-2020/19f34c9a3290feb87b00be0385cd84605ee8e649/src/assets/default-image.jpeg
--------------------------------------------------------------------------------
/src/data.js:
--------------------------------------------------------------------------------
1 | export const data = [
2 | { id: 1, name: 'john' },
3 | { id: 2, name: 'peter' },
4 | { id: 3, name: 'susan' },
5 | { id: 4, name: 'anna' },
6 | ];
7 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | ===============
3 | Variables
4 | ===============
5 | */
6 |
7 | :root {
8 | /* dark shades of primary color*/
9 | --clr-primary-1: hsl(205, 86%, 17%);
10 | --clr-primary-2: hsl(205, 77%, 27%);
11 | --clr-primary-3: hsl(205, 72%, 37%);
12 | --clr-primary-4: hsl(205, 63%, 48%);
13 | /* primary/main color */
14 | --clr-primary-5: hsl(205, 78%, 60%);
15 | /* lighter shades of primary color */
16 | --clr-primary-6: hsl(205, 89%, 70%);
17 | --clr-primary-7: hsl(205, 90%, 76%);
18 | --clr-primary-8: hsl(205, 86%, 81%);
19 | --clr-primary-9: hsl(205, 90%, 88%);
20 | --clr-primary-10: hsl(205, 100%, 96%);
21 | /* darkest grey - used for headings */
22 | --clr-grey-1: hsl(209, 61%, 16%);
23 | --clr-grey-2: hsl(211, 39%, 23%);
24 | --clr-grey-3: hsl(209, 34%, 30%);
25 | --clr-grey-4: hsl(209, 28%, 39%);
26 | /* grey used for paragraphs */
27 | --clr-grey-5: hsl(210, 22%, 49%);
28 | --clr-grey-6: hsl(209, 23%, 60%);
29 | --clr-grey-7: hsl(211, 27%, 70%);
30 | --clr-grey-8: hsl(210, 31%, 80%);
31 | --clr-grey-9: hsl(212, 33%, 89%);
32 | --clr-grey-10: hsl(210, 36%, 96%);
33 | --clr-white: #fff;
34 | --clr-red-dark: hsl(360, 67%, 44%);
35 | --clr-red-light: hsl(360, 71%, 66%);
36 | --clr-green-dark: hsl(125, 67%, 44%);
37 | --clr-green-light: hsl(125, 71%, 66%);
38 | --clr-black: #222;
39 | --transition: all 0.3s linear;
40 | --spacing: 0.1rem;
41 | --radius: 0.25rem;
42 | --light-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
43 | --dark-shadow: 0 5px 15px rgba(0, 0, 0, 0.4);
44 | --max-width: 1170px;
45 | --fixed-width: 450px;
46 | --clr-orange-1: hsl(12, 83%, 98%);
47 | --clr-orange-2: hsl(14, 91%, 95%);
48 | --clr-orange-3: hsl(12, 89%, 89%);
49 | --clr-orange-4: hsl(13, 87%, 82%);
50 | --clr-orange-5: hsl(13, 88%, 68%);
51 | --clr-orange-6: hsl(13, 88%, 55%);
52 | --clr-orange-7: hsl(13, 74%, 49%);
53 | --clr-orange-8: hsl(13, 74%, 33%);
54 | --clr-orange-9: hsl(13, 73%, 25%);
55 | --clr-orange-10: hsl(13, 73%, 16%);
56 | }
57 | /*
58 | ===============
59 | Global Styles
60 | ===============
61 | */
62 |
63 | *,
64 | ::after,
65 | ::before {
66 | margin: 0;
67 | padding: 0;
68 | box-sizing: border-box;
69 | }
70 | body {
71 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
72 | Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
73 | background: var(--clr-grey-10);
74 | color: var(--clr-grey-1);
75 | line-height: 1.5;
76 | font-size: 0.875rem;
77 | }
78 | ul {
79 | list-style-type: none;
80 | }
81 | a {
82 | text-decoration: none;
83 | }
84 | h1,
85 | h2,
86 | h3,
87 | h4 {
88 | letter-spacing: var(--spacing);
89 | text-transform: capitalize;
90 | line-height: 1.25;
91 | margin-bottom: 0.75rem;
92 | }
93 | h1 {
94 | font-size: 3rem;
95 | }
96 | h2 {
97 | font-size: 2rem;
98 | }
99 | h3 {
100 | font-size: 1.25rem;
101 | }
102 | h4 {
103 | font-size: 0.875rem;
104 | }
105 | p {
106 | margin-bottom: 1.25rem;
107 | color: var(--clr-grey-5);
108 | }
109 | @media screen and (min-width: 800px) {
110 | h1 {
111 | font-size: 4rem;
112 | }
113 | h2 {
114 | font-size: 2.5rem;
115 | }
116 | h3 {
117 | font-size: 1.75rem;
118 | }
119 | h4 {
120 | font-size: 1rem;
121 | }
122 | body {
123 | font-size: 1rem;
124 | }
125 | h1,
126 | h2,
127 | h3,
128 | h4 {
129 | line-height: 1;
130 | }
131 | }
132 | /* global classes */
133 |
134 | /* section */
135 | .section,
136 | .container {
137 | width: 90vw;
138 | margin: 0 auto;
139 | max-width: var(--max-width);
140 | }
141 |
142 | @media screen and (min-width: 992px) {
143 | .section {
144 | width: 95vw;
145 | }
146 | }
147 |
148 | .container {
149 | text-align: center;
150 | margin-top: 5rem;
151 | }
152 | .btn {
153 | display: inline-block;
154 | background: var(--clr-primary-5);
155 | color: var(--clr-white);
156 | padding: 0.25rem 0.75rem;
157 | border-radius: var(--radius);
158 | border-color: transparent;
159 | text-transform: capitalize;
160 | font-size: 1rem;
161 | letter-spacing: var(--spacing);
162 | margin-top: 2rem;
163 | margin-left: 0.5rem;
164 | margin-right: 0.5rem;
165 | cursor: pointer;
166 | transition: var(--transition);
167 | }
168 | .btn:hover {
169 | background: var(--clr-primary-1);
170 | color: var(--clr-primary-5);
171 | }
172 | .item {
173 | background: var(--clr-white);
174 | display: flex;
175 | justify-content: space-between;
176 | max-width: var(--fixed-width);
177 | margin: 2rem auto;
178 | align-items: center;
179 | border-radius: var(--radius);
180 | }
181 | .item button,
182 | .item a {
183 | background: transparent;
184 | border-color: transparent;
185 | color: var(--clr-primary-5);
186 | letter-spacing: var(--spacing);
187 | cursor: pointer;
188 | }
189 | .item {
190 | padding: 1rem 2rem;
191 | }
192 | .item h4 {
193 | margin-bottom: 0;
194 | }
195 | .item p {
196 | margin-bottom: 0;
197 | }
198 | .modal {
199 | position: absolute;
200 | top: 2rem;
201 | left: 50%;
202 | transform: translateX(-50%);
203 | background: var(--clr-white);
204 | display: inline-block;
205 | padding: 0.25rem 1rem;
206 | border-radius: var(--radius);
207 | text-transform: capitalize;
208 | }
209 |
210 | .modal p {
211 | margin-bottom: 0;
212 | color: var(--clr-red-dark);
213 | }
214 | .form {
215 | background: var(--clr-white);
216 | max-width: var(--fixed-width);
217 | margin: 0 auto;
218 | margin-bottom: 4rem;
219 | padding: 1rem 2rem;
220 | border-radius: var(--radius);
221 | }
222 | .form input {
223 | background: var(--clr-grey-10);
224 | border-color: transparent;
225 | border-radius: var(--radius);
226 | padding: 0.25rem 0.5rem;
227 | }
228 | .form-control {
229 | margin: 0.5rem 0;
230 | display: grid;
231 | grid-template-columns: 100px 1fr;
232 | align-items: center;
233 | }
234 | .form button {
235 | display: inline-block;
236 | background: var(--clr-black);
237 | color: var(--clr-white);
238 | border-color: transparent;
239 | margin-top: 1rem;
240 | letter-spacing: var(--spacing);
241 | padding: 0.15rem 0.25rem;
242 | text-transform: capitalize;
243 | border-radius: var(--radius);
244 | cursor: pointer;
245 | }
246 | .nav-links {
247 | max-width: var(--fixed-width);
248 | margin: 0 auto;
249 | margin-bottom: 4rem;
250 | display: grid;
251 | grid-template-columns: repeat(3, 1fr);
252 | }
253 | .nav-links a {
254 | color: var(--clr-grey-5);
255 | }
256 | .users {
257 | display: grid;
258 | grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
259 | gap: 2rem;
260 | margin: 3rem auto;
261 | }
262 | .users li {
263 | width: 100%;
264 | display: flex;
265 | align-items: center;
266 | background: var(--clr-white);
267 | padding: 1rem 2rem;
268 | border-radius: var(--radius);
269 | text-align: left;
270 | }
271 | .users img {
272 | width: 50px;
273 | height: 50px;
274 | border-radius: 50%;
275 | margin-right: 1rem;
276 | }
277 | .users h4 {
278 | margin-bottom: 0.15rem;
279 | }
280 | .users a {
281 | color: var(--clr-grey-5);
282 | text-transform: capitalize;
283 | }
284 |
285 | .products {
286 | margin: 4rem 0;
287 | display: grid;
288 | gap: 2rem;
289 | }
290 | @media screen and (min-width: 576px) {
291 | .products {
292 | grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
293 | }
294 | }
295 | .product {
296 | background: var(--clr-white);
297 | border-radius: var(--radius);
298 | }
299 | .product img {
300 | border-top-left-radius: var(--radius);
301 | border-top-right-radius: var(--radius);
302 |
303 | width: 100%;
304 | height: 15rem;
305 | object-fit: cover;
306 | }
307 | .product h4 {
308 | margin-top: 1rem;
309 | }
310 |
311 | .product button {
312 | margin-bottom: 1rem;
313 | background: var(--clr-primary-5);
314 | border-radius: var(--radius);
315 | border-color: transparent;
316 | color: var(--clr-white);
317 | padding: 0.25rem 0.5rem;
318 | text-transform: capitalize;
319 | cursor: pointer;
320 | }
321 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 |
6 | ReactDOM.render(
7 |
8 |
9 | ,
10 | document.getElementById('root')
11 | );
12 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/final/1-error-example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const ErrorExample = () => {
4 | let title = 'random title';
5 |
6 | const handleClick = () => {
7 | title = 'hello people';
8 | console.log(title);
9 | };
10 | return (
11 |
12 | {title}
13 |
16 |
17 | );
18 | };
19 |
20 | export default ErrorExample;
21 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/final/2-useState-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // starts with use
3 | // component must be uppercase
4 | // invoke inside function/component body
5 | // don't call hooks conditonally
6 |
7 | const UseStateBasics = () => {
8 | // console.log(useState());
9 | // const value = useState()[0];
10 | // const handler = useState()[1];
11 | // console.log(value, handler);
12 |
13 | const [text, setText] = useState('random title');
14 | const handleClick = () => {
15 | if (text === 'random title') {
16 | setText('hello world');
17 | } else {
18 | setText('random title');
19 | }
20 | };
21 |
22 | return (
23 |
24 | {text}
25 |
28 |
29 | );
30 | };
31 |
32 | export default UseStateBasics;
33 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/final/3-useState-array.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { data } from '../../../data';
3 | const UseStateArray = () => {
4 | const [people, setPeople] = React.useState(data);
5 |
6 | const removeItem = (id) => {
7 | let newPeople = people.filter((person) => person.id !== id);
8 | setPeople(newPeople);
9 | };
10 | return (
11 | <>
12 | {people.map((person) => {
13 | const { id, name } = person;
14 | return (
15 |
16 |
{name}
17 |
18 |
19 | );
20 | })}
21 |
24 | >
25 | );
26 | };
27 |
28 | export default UseStateArray;
29 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/final/4-useState-object.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const UseStateObject = () => {
4 | const [person, setPerson] = useState({
5 | name: 'peter',
6 | age: 24,
7 | message: 'random message',
8 | });
9 |
10 | // const [name,setName] = useState('peter')
11 | // const [age,setAge] = useState(24)
12 | // const [message,setMessage] = useState('random message')
13 |
14 | const changeMessage = () => {
15 | setPerson({ ...person, message: 'hello world' });
16 | // setMessage('hello world')
17 | };
18 |
19 | return (
20 | <>
21 | {person.name}
22 | {person.age}
23 | {person.message}
24 |
27 | >
28 | );
29 | };
30 |
31 | export default UseStateObject;
32 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/final/5-useState-counter.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const UseStateCounter = () => {
4 | const [value, setValue] = useState(0);
5 |
6 | const reset = () => {
7 | setValue(0);
8 | };
9 |
10 | const complexIncrease = () => {
11 | setTimeout(() => {
12 | // setValue(value + 1);
13 | setValue((prevState) => {
14 | return prevState + 1;
15 | });
16 | }, 2000);
17 | };
18 |
19 | return (
20 | <>
21 |
22 | regular counter
23 | {value}
24 |
27 |
30 |
33 |
34 |
35 | more complex counter
36 | {value}
37 |
40 |
41 | >
42 | );
43 | };
44 |
45 | export default UseStateCounter;
46 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/setup/1-error-example.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const ErrorExample = () => {
4 | return useState error example
;
5 | };
6 |
7 | export default ErrorExample;
8 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/setup/2-useState-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const UseStateBasics = () => {
4 | return useState basic example
;
5 | };
6 |
7 | export default UseStateBasics;
8 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/setup/3-useState-array.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { data } from '../../../data';
3 |
4 | const UseStateArray = () => {
5 | return useState array example
;
6 | };
7 |
8 | export default UseStateArray;
9 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/setup/4-useState-object.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const UseStateObject = () => {
4 | return useState object example
;
5 | };
6 |
7 | export default UseStateObject;
8 |
--------------------------------------------------------------------------------
/src/tutorial/1-useState/setup/5-useState-counter.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | const UseStateCounter = () => {
4 | return useState counter example
;
5 | };
6 |
7 | export default UseStateCounter;
8 |
--------------------------------------------------------------------------------
/src/tutorial/10-prop-types/final/Product.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import defaultImage from '../../../assets/default-image.jpeg';
4 | const Product = ({ image, name, price }) => {
5 | const url = image && image.url;
6 | return (
7 |
8 |
9 | {name}
10 | ${price || 3.99}
11 |
12 | );
13 | };
14 |
15 | Product.propTypes = {
16 | image: PropTypes.object.isRequired,
17 | name: PropTypes.string.isRequired,
18 | price: PropTypes.number.isRequired,
19 | };
20 | // Product.defaultProps = {
21 | // name: 'default name',
22 | // price: 3.99,
23 | // image: defaultImage,
24 | // };
25 |
26 | export default Product;
27 |
--------------------------------------------------------------------------------
/src/tutorial/10-prop-types/final/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Product from './Product'
3 | import { useFetch } from '../../9-custom-hooks/final/2-useFetch'
4 | // import defaultImage from '../../../assets/default-image.jpeg';
5 |
6 | // ATTENTION!!!!!!!!!!
7 | // I SWITCHED TO PERMANENT DOMAIN
8 | const url = 'https://course-api.com/react-prop-types-example'
9 |
10 | const Index = () => {
11 | const { products } = useFetch(url)
12 | return (
13 |
14 |
products
15 | {/*

*/}
16 |
17 | {products.map((product) => {
18 | return
19 | })}
20 |
21 |
22 | )
23 | }
24 |
25 | export default Index
26 |
--------------------------------------------------------------------------------
/src/tutorial/10-prop-types/final/testing.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const testing = (props) => {
5 | return ;
6 | };
7 |
8 | testing.propTypes = {
9 | name: PropTypes.array.isRequired,
10 | };
11 |
12 | export default testing;
13 |
--------------------------------------------------------------------------------
/src/tutorial/10-prop-types/setup/Product.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Product = () => {
4 | return single product;
5 | };
6 |
7 | export default Product;
8 |
--------------------------------------------------------------------------------
/src/tutorial/10-prop-types/setup/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Product from './Product'
3 | import { useFetch } from '../../9-custom-hooks/final/2-useFetch'
4 |
5 | // ATTENTION!!!!!!!!!!
6 | // I SWITCHED TO PERMANENT DOMAIN
7 | const url = 'https://course-api.com/react-prop-types-example'
8 |
9 | const Index = () => {
10 | const { products } = useFetch(url)
11 | return (
12 |
13 |
products
14 |
15 | {products.map((product) => {
16 | return
17 | })}
18 |
19 |
20 | )
21 | }
22 |
23 | export default Index
24 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/ReactRouterInfo.md:
--------------------------------------------------------------------------------
1 | !(react router)[https://reactrouter.com/web/guides/quick-start]
2 |
3 | ```
4 | npm install react-router-dom
5 |
6 | ```
7 |
8 | "react-router-dom": "^5.2.0"
9 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 |
6 |
About Page
7 |
8 | );
9 | };
10 |
11 | export default About;
12 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/Error.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | const Error = () => {
4 | return (
5 |
6 |
Error Page
7 |
8 | Back Home
9 |
10 |
11 | );
12 | };
13 |
14 | export default Error;
15 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Home = () => {
4 | return (
5 |
6 |
Home Page
7 |
shake and bake
8 |
9 | );
10 | };
11 |
12 | export default Home;
13 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | const Navbar = () => {
4 | return (
5 |
18 | );
19 | };
20 |
21 | export default Navbar;
22 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/People.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { data } from '../../../data';
3 | import { Link } from 'react-router-dom';
4 | const People = () => {
5 | const [people, setPeople] = useState(data);
6 | return (
7 |
8 |
People Page
9 | {people.map((person) => {
10 | return (
11 |
12 |
{person.name}
13 | Learn More
14 |
15 | );
16 | })}
17 |
18 | );
19 | };
20 |
21 | export default People;
22 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/Person.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { data } from '../../../data';
3 | import { Link, useParams } from 'react-router-dom';
4 | const Person = () => {
5 | const [name, setName] = useState('default name');
6 | const { id } = useParams();
7 |
8 | useEffect(() => {
9 | const newPerson = data.find((person) => person.id === parseInt(id));
10 | setName(newPerson.name);
11 | }, []);
12 | return (
13 |
14 |
{name}
15 |
16 | Back To People
17 |
18 |
19 | );
20 | };
21 |
22 | export default Person;
23 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/final/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // react router
3 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
4 | // pages
5 | import Home from './Home';
6 | import About from './About';
7 | import People from './People';
8 | import Error from './Error';
9 | import Person from './Person';
10 | // navbar
11 | import Navbar from './Navbar';
12 | const ReactRouterSetup = () => {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | }>
27 |
28 |
29 |
30 |
31 |
32 | );
33 | };
34 |
35 | export default ReactRouterSetup;
36 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 |
6 |
About Page
7 |
8 | );
9 | };
10 |
11 | export default About;
12 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/Error.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | const Error = () => {
4 | return (
5 |
6 |
Error Page
7 |
8 | );
9 | };
10 |
11 | export default Error;
12 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const Home = () => {
4 | return (
5 |
6 |
Home Page
7 |
8 | );
9 | };
10 |
11 | export default Home;
12 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link } from 'react-router-dom';
3 | const Navbar = () => {
4 | return ;
5 | };
6 |
7 | export default Navbar;
8 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/People.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { data } from '../../../data';
3 | import { Link } from 'react-router-dom';
4 | const People = () => {
5 | const [people, setPeople] = useState(data);
6 | return (
7 |
8 |
People Page
9 | {people.map((person) => {
10 | return (
11 |
12 |
{person.name}
13 |
14 | );
15 | })}
16 |
17 | );
18 | };
19 |
20 | export default People;
21 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/Person.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | import { data } from '../../../data';
3 | import { Link, useParams } from 'react-router-dom';
4 | const Person = () => {
5 | return (
6 |
7 |
person
8 |
9 | );
10 | };
11 |
12 | export default Person;
13 |
--------------------------------------------------------------------------------
/src/tutorial/11-react-router/setup/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | // react router
3 | import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
4 | // pages
5 | import Home from './Home';
6 | import About from './About';
7 | import People from './People';
8 | import Error from './Error';
9 | import Person from './Person';
10 | // navbar
11 | import Navbar from './Navbar';
12 | const ReactRouterSetup = () => {
13 | return react router
;
14 | };
15 |
16 | export default ReactRouterSetup;
17 |
--------------------------------------------------------------------------------
/src/tutorial/12-memo-useMemo-useCallback/final/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useCallback, useMemo } from 'react'
2 | import { useFetch } from '../../9-custom-hooks/final/2-useFetch'
3 |
4 | // ATTENTION!!!!!!!!!!
5 | // I SWITCHED TO PERMANENT DOMAIN
6 | const url = 'https://course-api.com/javascript-store-products'
7 |
8 | // every time props or state changes, component re-renders
9 | const calculateMostExpensive = (data) => {
10 | return (
11 | data.reduce((total, item) => {
12 | const price = item.fields.price
13 | if (price >= total) {
14 | total = price
15 | }
16 | return total
17 | }, 0) / 100
18 | )
19 | }
20 | const Index = () => {
21 | const { products } = useFetch(url)
22 | const [count, setCount] = useState(0)
23 | const [cart, setCart] = useState(0)
24 |
25 | const addToCart = useCallback(() => {
26 | setCart(cart + 1)
27 | }, [cart])
28 |
29 | const mostExpensive = useMemo(() => calculateMostExpensive(products), [
30 | products,
31 | ])
32 | return (
33 | <>
34 | Count : {count}
35 |
38 | cart : {cart}
39 | Most Expensive : ${mostExpensive}
40 |
41 | >
42 | )
43 | }
44 |
45 | const BigList = React.memo(({ products, addToCart }) => {
46 | // useEffect(() => {
47 | // console.count('hello from big list');
48 | // });
49 |
50 | return (
51 |
52 | {products.map((product) => {
53 | return (
54 |
59 | )
60 | })}
61 |
62 | )
63 | })
64 |
65 | const SingleProduct = ({ fields, addToCart }) => {
66 | let { name, price } = fields
67 | price = price / 100
68 | const image = fields.image[0].url
69 |
70 | // useEffect(() => {
71 | // console.count('hello from product');
72 | // });
73 | return (
74 |
75 |
76 | {name}
77 | ${price}
78 |
79 |
80 | )
81 | }
82 | export default Index
83 |
--------------------------------------------------------------------------------
/src/tutorial/12-memo-useMemo-useCallback/setup/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback, useMemo } from 'react'
2 | import { useFetch } from '../../9-custom-hooks/final/2-useFetch'
3 |
4 | // ATTENTION!!!!!!!!!!
5 | // I SWITCHED TO PERMANENT DOMAIN
6 | const url = 'https://course-api.com/javascript-store-products'
7 |
8 | // every time props or state changes, component re-renders
9 |
10 | const Index = () => {
11 | const { products } = useFetch(url)
12 | const [count, setCount] = useState(0)
13 |
14 | return (
15 | <>
16 | Count : {count}
17 |
20 |
21 | >
22 | )
23 | }
24 |
25 | const BigList = ({ products }) => {
26 | return (
27 |
28 | {products.map((product) => {
29 | return
30 | })}
31 |
32 | )
33 | }
34 |
35 | const SingleProduct = ({ fields }) => {
36 | let { name, price } = fields
37 | price = price / 100
38 | const image = fields.image[0].url
39 |
40 | return (
41 |
42 |
43 | {name}
44 | ${price}
45 |
46 | )
47 | }
48 | export default Index
49 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/final/1-useEffect-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | // by default runs after every re-render
3 | // cleanup function
4 | // second parameter
5 | const UseEffectBasics = () => {
6 | const [value, setValue] = useState(0);
7 | useEffect(() => {
8 | console.log('call useEffect');
9 | if (value > 0) {
10 | document.title = `New Messages(${value})`;
11 | }
12 | });
13 |
14 | console.log('render component');
15 | return (
16 | <>
17 | {value}
18 |
21 | >
22 | );
23 | };
24 |
25 | export default UseEffectBasics;
26 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/final/2-useEffect-cleanup.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | // cleanup function
4 | // second argument
5 |
6 | const UseEffectCleanup = () => {
7 | const [size, setSize] = useState(window.innerWidth);
8 |
9 | const checkSize = () => {
10 | setSize(window.innerWidth);
11 | };
12 |
13 | useEffect(() => {
14 | console.log('useEffect');
15 | window.addEventListener('resize', checkSize);
16 | return () => {
17 | console.log('cleanup');
18 | window.removeEventListener('resize', checkSize);
19 | };
20 | }, []);
21 | console.log('render');
22 | return (
23 | <>
24 | window
25 | {size} PX
26 | >
27 | );
28 | };
29 |
30 | export default UseEffectCleanup;
31 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/final/3-useEffect-fetch-data.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | const url = 'https://api.github.com/users';
4 |
5 | // second argument
6 |
7 | const UseEffectFetchData = () => {
8 | const [users, setUsers] = useState([]);
9 |
10 | const getUsers = async () => {
11 | const response = await fetch(url);
12 | const users = await response.json();
13 | setUsers(users);
14 | // console.log(users);
15 | };
16 |
17 | useEffect(() => {
18 | getUsers();
19 | }, []);
20 | return (
21 | <>
22 | github users
23 |
24 | {users.map((user) => {
25 | const { id, login, avatar_url, html_url } = user;
26 | return (
27 | -
28 |
29 |
33 |
34 | );
35 | })}
36 |
37 | >
38 | );
39 | };
40 |
41 | export default UseEffectFetchData;
42 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/setup/1-useEffect-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | // by default runs after every re-render
3 | // cleanup function
4 | // second parameter
5 | const UseEffectBasics = () => {
6 | return useEffect Basics
;
7 | };
8 |
9 | export default UseEffectBasics;
10 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/setup/2-useEffect-cleanup.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | // cleanup function
4 | // second argument
5 |
6 | const UseEffectCleanup = () => {
7 | return useEffect cleanup
;
8 | };
9 |
10 | export default UseEffectCleanup;
11 |
--------------------------------------------------------------------------------
/src/tutorial/2-useEffect/setup/3-useEffect-fetch-data.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | const url = 'https://api.github.com/users';
4 |
5 | const UseEffectFetchData = () => {
6 | return fetch data
;
7 | };
8 |
9 | export default UseEffectFetchData;
10 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/final/1-multiple-returns.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | const url = 'https://api.github.com/users/QuincyLarson';
3 | const MultipleReturns = () => {
4 | const [isLoading, setIsLoading] = useState(true);
5 | const [isError, setIsError] = useState(false);
6 | const [user, setUser] = useState('default user');
7 |
8 | useEffect(() => {
9 | fetch(url)
10 | .then((resp) => {
11 | if (resp.status >= 200 && resp.status <= 299) {
12 | return resp.json();
13 | } else {
14 | setIsLoading(false);
15 | setIsError(true);
16 | throw new Error(resp.statusText);
17 | }
18 | })
19 | .then((user) => {
20 | const { login } = user;
21 | setUser(login);
22 | setIsLoading(false);
23 | })
24 | .catch((error) => console.log(error));
25 | }, []);
26 |
27 | if (isLoading) {
28 | return (
29 |
30 |
Loading...
31 |
32 | );
33 | }
34 | if (isError) {
35 | return (
36 |
37 |
Error....
38 |
39 | );
40 | }
41 | return (
42 |
43 |
{user}
44 |
45 | );
46 | };
47 |
48 | export default MultipleReturns;
49 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/final/2-short-circuit.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // short-circuit evaluation
3 | // ternary operator
4 |
5 | const ShortCircuit = () => {
6 | const [text, setText] = useState('');
7 | const [isError, setIsError] = useState(false);
8 | // const firstValue = text || 'hello world';
9 | // const secondValue = text && 'hello world';
10 |
11 | return (
12 | <>
13 | {/* {firstValue}
14 | value : {secondValue}
*/}
15 | {/* {if(){console.log('hello world')}} */}
16 | {text || 'john doe'}
17 |
20 | {isError && Error...
}
21 | {isError ? (
22 | there is an error...
23 | ) : (
24 |
25 |
there is no error
26 |
27 | )}
28 | >
29 | );
30 | };
31 |
32 | export default ShortCircuit;
33 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/final/3-show-hide.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | const ShowHide = () => {
4 | const [show, setShow] = useState(false);
5 | return (
6 | <>
7 |
10 | {show && }
11 | >
12 | );
13 | };
14 |
15 | const Item = () => {
16 | const [size, setSize] = useState(window.innerWidth);
17 | const checkSize = () => {
18 | setSize(window.innerWidth);
19 | };
20 | useEffect(() => {
21 | window.addEventListener('resize', checkSize);
22 | return () => {
23 | window.removeEventListener('resize', checkSize);
24 | };
25 | }, []);
26 |
27 | return (
28 |
29 |
Window
30 | size : {size}
31 |
32 | );
33 | };
34 |
35 | export default ShowHide;
36 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/setup/1-multiple-returns.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 | const url = 'https://api.github.com/users/QuincyLarson';
3 | const MultipleReturns = () => {
4 | return multiple returns
;
5 | };
6 |
7 | export default MultipleReturns;
8 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/setup/2-short-circuit.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // short-circuit evaluation
3 | // ternary operator
4 |
5 | const ShortCircuit = () => {
6 | // const firstValue = text || 'hello world';
7 | // const secondValue = text && 'hello world';
8 |
9 | return short circuit
;
10 | };
11 |
12 | export default ShortCircuit;
13 |
--------------------------------------------------------------------------------
/src/tutorial/3-conditional-rendering/setup/3-show-hide.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react';
2 |
3 | const ShowHide = () => {
4 | return show/hide
;
5 | };
6 |
7 | export default ShowHide;
8 |
--------------------------------------------------------------------------------
/src/tutorial/4-forms/final/1-controlled-inputs.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // JS
3 | // const input = document.getElementById('myText');
4 | // const inputValue = input.value
5 | // React
6 | // value, onChange
7 |
8 | const ControlledInputs = () => {
9 | const [firstName, setFirstName] = useState('');
10 | const [email, setEmail] = useState('');
11 | const [people, setPeople] = useState([]);
12 |
13 | const handleSubmit = (e) => {
14 | e.preventDefault();
15 | if (firstName && email) {
16 | const person = { id: new Date().getTime().toString(), firstName, email };
17 | console.log(person);
18 | setPeople((people) => {
19 | return [...people, person];
20 | });
21 | setFirstName('');
22 | setEmail('');
23 | } else {
24 | console.log('empty values');
25 | }
26 | };
27 | return (
28 | <>
29 |
30 |
53 | {people.map((person, index) => {
54 | const { id, firstName, email } = person;
55 | return (
56 |
57 |
{firstName}
58 |
{email}
59 |
60 | );
61 | })}
62 |
63 | >
64 | );
65 | };
66 |
67 | export default ControlledInputs;
68 |
--------------------------------------------------------------------------------
/src/tutorial/4-forms/final/2-multiple-inputs.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // JS
3 | // const input = document.getElementById('myText');
4 | // const inputValue = input.value
5 | // React
6 | // value, onChange
7 |
8 | const ControlledInputs = () => {
9 | const [person, setPerson] = useState({ firstName: '', email: '', age: '' });
10 | const [people, setPeople] = useState([]);
11 | const handleChange = (e) => {
12 | const name = e.target.name;
13 | const value = e.target.value;
14 | setPerson({ ...person, [name]: value });
15 | };
16 | const handleSubmit = (e) => {
17 | e.preventDefault();
18 | if (person.firstName && person.email && person.age) {
19 | const newPerson = { ...person, id: new Date().getTime().toString() };
20 | setPeople([...people, newPerson]);
21 | setPerson({ firstName: '', email: '', age: '' });
22 | }
23 | };
24 | return (
25 | <>
26 |
27 |
62 |
63 |
64 | {people.map((person) => {
65 | const { id, firstName, email, age } = person;
66 | return (
67 |
68 |
{firstName}
69 |
{email}
70 |
{age}
71 |
72 | );
73 | })}
74 |
75 | >
76 | );
77 | };
78 |
79 | export default ControlledInputs;
80 |
--------------------------------------------------------------------------------
/src/tutorial/4-forms/setup/1-controlled-inputs.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // JS
3 | // const input = document.getElementById('myText');
4 | // const inputValue = input.value
5 | // React
6 | // value, onChange
7 |
8 | const ControlledInputs = () => {
9 | return controlled inputs
;
10 | };
11 |
12 | export default ControlledInputs;
13 |
--------------------------------------------------------------------------------
/src/tutorial/4-forms/setup/2-multiple-inputs.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | // JS
3 | // const input = document.getElementById('myText');
4 | // const inputValue = input.value
5 | // React
6 | // value, onChange
7 | // dynamic object keys
8 |
9 | const ControlledInputs = () => {
10 | const [firstName, setFirstName] = useState('');
11 | const [email, setEmail] = useState('');
12 | const [people, setPeople] = useState([]);
13 |
14 | const handleSubmit = (e) => {
15 | e.preventDefault();
16 | if (firstName && email) {
17 | const person = { id: new Date().getTime().toString(), firstName, email };
18 | console.log(person);
19 | setPeople((people) => {
20 | return [...people, person];
21 | });
22 | setFirstName('');
23 | setEmail('');
24 | } else {
25 | console.log('empty values');
26 | }
27 | };
28 | return (
29 | <>
30 |
31 |
54 | {people.map((person, index) => {
55 | const { id, firstName, email } = person;
56 | return (
57 |
58 |
{firstName}
59 |
{email}
60 |
61 | );
62 | })}
63 |
64 | >
65 | );
66 | };
67 |
68 | export default ControlledInputs;
69 |
--------------------------------------------------------------------------------
/src/tutorial/5-useRef/final/1-useRef-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 |
3 | // preserves value
4 | // DOES NOT trigger re-render
5 | // target DOM nodes/elements
6 |
7 | const UseRefBasics = () => {
8 | const refContainer = useRef(null);
9 |
10 | const handleSubmit = (e) => {
11 | e.preventDefault();
12 | console.log(refContainer.current.value);
13 | };
14 | useEffect(() => {
15 | console.log(refContainer.current);
16 | refContainer.current.focus();
17 | });
18 |
19 | return (
20 | <>
21 |
27 | >
28 | );
29 | };
30 |
31 | export default UseRefBasics;
32 |
--------------------------------------------------------------------------------
/src/tutorial/5-useRef/setup/1-useRef-basics.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useRef } from 'react';
2 |
3 | // preserves value
4 | // DOES NOT trigger re-render
5 | // target DOM nodes/elements
6 |
7 | const UseRefBasics = () => {
8 | return useRef
;
9 | };
10 |
11 | export default UseRefBasics;
12 |
--------------------------------------------------------------------------------
/src/tutorial/6-useReducer/final/Modal.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 |
3 | const Modal = ({ modalContent, closeModal }) => {
4 | useEffect(() => {
5 | setTimeout(() => {
6 | closeModal();
7 | }, 3000);
8 | });
9 | return (
10 |
13 | );
14 | };
15 |
16 | export default Modal;
17 |
--------------------------------------------------------------------------------
/src/tutorial/6-useReducer/final/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useReducer } from 'react';
2 | import Modal from './Modal';
3 | import { data } from '../../../data';
4 | // reducer function
5 | import { reducer } from './reducer';
6 | const defaultState = {
7 | people: [],
8 | isModalOpen: false,
9 | modalContent: '',
10 | };
11 | const Index = () => {
12 | const [name, setName] = useState('');
13 | const [state, dispatch] = useReducer(reducer, defaultState);
14 | const handleSubmit = (e) => {
15 | e.preventDefault();
16 | if (name) {
17 | const newItem = { id: new Date().getTime().toString(), name };
18 | dispatch({ type: 'ADD_ITEM', payload: newItem });
19 | setName('');
20 | } else {
21 | dispatch({ type: 'NO_VALUE' });
22 | }
23 | };
24 | const closeModal = () => {
25 | dispatch({ type: 'CLOSE_MODAL' });
26 | };
27 | return (
28 | <>
29 | {state.isModalOpen && (
30 |
31 | )}
32 |
42 | {state.people.map((person) => {
43 | return (
44 |
45 |
{person.name}
46 |
53 |
54 | );
55 | })}
56 | >
57 | );
58 | };
59 |
60 | export default Index;
61 |
--------------------------------------------------------------------------------
/src/tutorial/6-useReducer/final/reducer.js:
--------------------------------------------------------------------------------
1 | export const reducer = (state, action) => {
2 | if (action.type === 'ADD_ITEM') {
3 | const newPeople = [...state.people, action.payload];
4 | return {
5 | ...state,
6 | people: newPeople,
7 | isModalOpen: true,
8 | modalContent: 'item added',
9 | };
10 | }
11 | if (action.type === 'NO_VALUE') {
12 | return { ...state, isModalOpen: true, modalContent: 'please enter value' };
13 | }
14 | if (action.type === 'CLOSE_MODAL') {
15 | return { ...state, isModalOpen: false };
16 | }
17 | if (action.type === 'REMOVE_ITEM') {
18 | const newPeople = state.people.filter(
19 | (person) => person.id !== action.payload
20 | );
21 | return { ...state, people: newPeople };
22 | }
23 | throw new Error('no matching action type');
24 | };
25 |
--------------------------------------------------------------------------------
/src/tutorial/6-useReducer/setup/Modal.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 |
3 | const Modal = () => {
4 | return i'm modal
;
5 | };
6 |
7 | export default Modal;
8 |
--------------------------------------------------------------------------------
/src/tutorial/6-useReducer/setup/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useReducer } from 'react';
2 | import Modal from './Modal';
3 | import { data } from '../../../data';
4 | // reducer function
5 |
6 | const Index = () => {
7 | return useReducer
;
8 | };
9 |
10 | export default Index;
11 |
--------------------------------------------------------------------------------
/src/tutorial/7-prop-drilling/final/1-prop-drilling.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { data } from '../../../data';
3 | // more components
4 | // fix - context api, redux (for more complex cases)
5 |
6 | const PropDrilling = () => {
7 | const [people, setPeople] = useState(data);
8 | const removePerson = (id) => {
9 | setPeople((people) => {
10 | return people.filter((person) => person.id !== id);
11 | });
12 | };
13 | return (
14 |
15 | prop drilling
16 |
17 |
18 | );
19 | };
20 |
21 | const List = ({ people, removePerson }) => {
22 | return (
23 | <>
24 | {people.map((person) => {
25 | return (
26 |
31 | );
32 | })}
33 | >
34 | );
35 | };
36 |
37 | const SinglePerson = ({ id, name, removePerson }) => {
38 | return (
39 |
40 |
{name}
41 |
42 |
43 | );
44 | };
45 |
46 | export default PropDrilling;
47 |
--------------------------------------------------------------------------------
/src/tutorial/7-prop-drilling/setup/1-prop-drilling.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 |
3 | // more components
4 | // fix - context api, redux (for more complex cases)
5 |
6 | const PropDrilling = () => {
7 | return prop drilling
;
8 | };
9 |
10 | export default PropDrilling;
11 |
--------------------------------------------------------------------------------
/src/tutorial/8-useContext/final/1-context-api.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext } from 'react';
2 | import { data } from '../../../data';
3 | // more components
4 | // fix - context api, redux (for more complex cases)
5 |
6 | const PersonContext = React.createContext();
7 | // two components - Provider, Consumer
8 |
9 | const ContextAPI = () => {
10 | const [people, setPeople] = useState(data);
11 | const removePerson = (id) => {
12 | setPeople((people) => {
13 | return people.filter((person) => person.id !== id);
14 | });
15 | };
16 | return (
17 |
18 | Context API / useContext
19 |
20 |
21 | );
22 | };
23 |
24 | const List = () => {
25 | const mainData = useContext(PersonContext);
26 | console.log(mainData);
27 | return (
28 | <>
29 | {mainData.people.map((person) => {
30 | return ;
31 | })}
32 | >
33 | );
34 | };
35 |
36 | const SinglePerson = ({ id, name }) => {
37 | const { removePerson } = useContext(PersonContext);
38 |
39 | return (
40 |
41 |
{name}
42 |
43 |
44 | );
45 | };
46 |
47 | export default ContextAPI;
48 |
--------------------------------------------------------------------------------
/src/tutorial/8-useContext/setup/1-context-api.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useContext } from 'react';
2 | import { data } from '../../../data';
3 | // more components
4 | // fix - context api, redux (for more complex cases)
5 |
6 | const ContextAPI = () => {
7 | const [people, setPeople] = useState(data);
8 | const removePerson = (id) => {
9 | setPeople((people) => {
10 | return people.filter((person) => person.id !== id);
11 | });
12 | };
13 | return (
14 | <>
15 | prop drilling
16 |
17 | >
18 | );
19 | };
20 |
21 | const List = ({ people, removePerson }) => {
22 | return (
23 | <>
24 | {people.map((person) => {
25 | return (
26 |
31 | );
32 | })}
33 | >
34 | );
35 | };
36 |
37 | const SinglePerson = ({ id, name, removePerson }) => {
38 | return (
39 |
40 |
{name}
41 |
42 |
43 | );
44 | };
45 |
46 | export default ContextAPI;
47 |
--------------------------------------------------------------------------------
/src/tutorial/9-custom-hooks/final/1-fetch-example.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { useFetch } from './2-useFetch'
3 |
4 | // ATTENTION!!!!!!!!!!
5 | // I SWITCHED TO PERMANENT DOMAIN
6 | const url = 'https://course-api.com/javascript-store-products'
7 |
8 | const Example = () => {
9 | const { loading, products } = useFetch(url)
10 | console.log(products)
11 | return (
12 |
13 |
{loading ? 'loading...' : 'data'}
14 |
15 | )
16 | }
17 |
18 | export default Example
19 |
--------------------------------------------------------------------------------
/src/tutorial/9-custom-hooks/final/2-useFetch.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from 'react';
2 |
3 | export const useFetch = (url) => {
4 | const [loading, setLoading] = useState(true);
5 | const [products, setProducts] = useState([]);
6 |
7 | const getProducts = useCallback(async () => {
8 | const response = await fetch(url);
9 | const products = await response.json();
10 | setProducts(products);
11 | setLoading(false);
12 | }, [url]);
13 |
14 | useEffect(() => {
15 | getProducts();
16 | }, [url, getProducts]);
17 | return { loading, products };
18 | };
19 |
--------------------------------------------------------------------------------
/src/tutorial/9-custom-hooks/setup/1-fetch-example.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { useFetch } from './2-useFetch'
3 |
4 | // ATTENTION!!!!!!!!!!
5 | // I SWITCHED TO PERMANENT DOMAIN
6 | const url = 'https://course-api.com/javascript-store-products'
7 |
8 | const Example = () => {
9 | const [loading, setLoading] = useState(true)
10 | const [products, setProducts] = useState([])
11 |
12 | const getProducts = async () => {
13 | const response = await fetch(url)
14 | const products = await response.json()
15 | setProducts(products)
16 | setLoading(false)
17 | }
18 |
19 | useEffect(() => {
20 | getProducts()
21 | }, [url])
22 | console.log(products)
23 | return (
24 |
25 |
{loading ? 'loading...' : 'data'}
26 |
27 | )
28 | }
29 |
30 | export default Example
31 |
--------------------------------------------------------------------------------
/src/tutorial/9-custom-hooks/setup/2-useFetch.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 |
3 | export const useFetch = () => {};
4 |
--------------------------------------------------------------------------------