├── .gitignore
├── 02_create_a_react_app
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
└── vite.config.js
├── 03_creating_a_react_component
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.jsx
│ ├── Person.jsx
│ └── main.jsx
└── vite.config.js
├── 04_JSX
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.jsx
│ ├── Person.jsx
│ └── main.jsx
└── vite.config.js
├── 05_events
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.css
│ ├── People.jsx
│ ├── Person.jsx
│ └── main.jsx
└── vite.config.js
├── 06_styling
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.css
│ ├── People.jsx
│ ├── Person.jsx
│ ├── main.css
│ └── main.jsx
└── vite.config.js
├── 07_state
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.css
│ ├── People.jsx
│ ├── Person.jsx
│ ├── main.css
│ └── main.jsx
└── vite.config.js
├── 08_props
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.css
│ ├── People.jsx
│ ├── Person.jsx
│ ├── main.css
│ └── main.jsx
└── vite.config.js
├── 09_composition
├── .eslintrc.cjs
├── .gitignore
├── README.md
├── index.html
├── package.json
├── src
│ ├── App.jsx
│ ├── People.css
│ ├── People.jsx
│ ├── PeopleQuery.jsx
│ ├── Person.css
│ ├── Person.jsx
│ ├── main.css
│ └── main.jsx
└── vite.config.js
├── LICENSE
├── README.md
├── ReactCheatSheet.md
└── assets
├── Person.css
├── Person.html
├── README.md
└── fetchPeople.js
/.gitignore:
--------------------------------------------------------------------------------
1 | **/sensitiveConstants.js
2 | **/package-lock.json
3 | **/yarn.lock
4 |
5 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
6 |
7 | # dependencies
8 | **/node_modules
9 | **/.pnp
10 | **/.pnp.js
11 |
12 | # testing
13 | **/coverage
14 |
15 | # production
16 | **/build
17 |
18 | # misc
19 | **/.DS_Store
20 | **/.env.local
21 | **/.env.development.local
22 | **/.env.test.local
23 | **/.env.production.local
24 |
25 | **/npm-debug.log*
26 | **/yarn-debug.log*
27 | **/yarn-error.log*
28 |
--------------------------------------------------------------------------------
/02_create_a_react_app/.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 |
--------------------------------------------------------------------------------
/02_create_a_react_app/.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 |
--------------------------------------------------------------------------------
/02_create_a_react_app/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/02_create_a_react_app/README.md
--------------------------------------------------------------------------------
/02_create_a_react_app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/02_create_a_react_app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "react": "^18.3.1",
14 | "react-dom": "^18.3.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.3.3",
18 | "@types/react-dom": "^18.3.0",
19 | "@vitejs/plugin-react-swc": "^3.3.2",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/02_create_a_react_app/src/App.css:
--------------------------------------------------------------------------------
1 | #root {
2 | max-width: 1280px;
3 | margin: 0 auto;
4 | padding: 2rem;
5 | text-align: center;
6 | }
7 |
8 | .logo {
9 | height: 6em;
10 | padding: 1.5em;
11 | will-change: filter;
12 | transition: filter 300ms;
13 | }
14 | .logo:hover {
15 | filter: drop-shadow(0 0 2em #646cffaa);
16 | }
17 | .logo.react:hover {
18 | filter: drop-shadow(0 0 2em #61dafbaa);
19 | }
20 |
21 | @keyframes logo-spin {
22 | from {
23 | transform: rotate(0deg);
24 | }
25 | to {
26 | transform: rotate(360deg);
27 | }
28 | }
29 |
30 | @media (prefers-reduced-motion: no-preference) {
31 | a:nth-of-type(2) .logo {
32 | animation: logo-spin infinite 20s linear;
33 | }
34 | }
35 |
36 | .card {
37 | padding: 2em;
38 | }
39 |
40 | .read-the-docs {
41 | color: #888;
42 | }
43 |
--------------------------------------------------------------------------------
/02_create_a_react_app/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import './App.css'
3 |
4 | function App() {
5 | const [count, setCount] = useState(0)
6 |
7 | return (
8 | <>
9 | Vite + React
10 |
11 |
setCount((count) => count + 1)}>
12 | count is {count}
13 |
14 |
15 | Edit src/App.jsx
and save to test HMR
16 |
17 |
18 |
19 | Click on the Vite and React logos to learn more
20 |
21 | >
22 | )
23 | }
24 |
25 | export default App
26 |
--------------------------------------------------------------------------------
/02_create_a_react_app/src/index.css:
--------------------------------------------------------------------------------
1 | :root {
2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3 | line-height: 1.5;
4 | font-weight: 400;
5 |
6 | color-scheme: light dark;
7 | color: rgba(255, 255, 255, 0.87);
8 | background-color: #242424;
9 |
10 | font-synthesis: none;
11 | text-rendering: optimizeLegibility;
12 | -webkit-font-smoothing: antialiased;
13 | -moz-osx-font-smoothing: grayscale;
14 | -webkit-text-size-adjust: 100%;
15 | }
16 |
17 | a {
18 | font-weight: 500;
19 | color: #646cff;
20 | text-decoration: inherit;
21 | }
22 | a:hover {
23 | color: #535bf2;
24 | }
25 |
26 | body {
27 | margin: 0;
28 | display: flex;
29 | place-items: center;
30 | min-width: 320px;
31 | min-height: 100vh;
32 | }
33 |
34 | h1 {
35 | font-size: 3.2em;
36 | line-height: 1.1;
37 | }
38 |
39 | button {
40 | border-radius: 8px;
41 | border: 1px solid transparent;
42 | padding: 0.6em 1.2em;
43 | font-size: 1em;
44 | font-weight: 500;
45 | font-family: inherit;
46 | background-color: #1a1a1a;
47 | cursor: pointer;
48 | transition: border-color 0.25s;
49 | }
50 | button:hover {
51 | border-color: #646cff;
52 | }
53 | button:focus,
54 | button:focus-visible {
55 | outline: 4px auto -webkit-focus-ring-color;
56 | }
57 |
58 | @media (prefers-color-scheme: light) {
59 | :root {
60 | color: #213547;
61 | background-color: #ffffff;
62 | }
63 | a:hover {
64 | color: #747bff;
65 | }
66 | button {
67 | background-color: #f9f9f9;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/02_create_a_react_app/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 |
--------------------------------------------------------------------------------
/02_create_a_react_app/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/.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 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/.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 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/03_creating_a_react_component/README.md
--------------------------------------------------------------------------------
/03_creating_a_react_component/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "react": "^18.3.1",
14 | "react-dom": "^18.3.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.3.3",
18 | "@types/react-dom": "^18.3.0",
19 | "@vitejs/plugin-react-swc": "^3.3.2",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { People } from "./People"
2 |
3 | function App() {
4 | return (
5 | <>
6 |
8 |
9 |
10 |
11 |
12 | Copyright © Us.com 2029
13 |
14 | >
15 | )
16 | }
17 |
18 | export default App
19 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/src/People.jsx:
--------------------------------------------------------------------------------
1 | import { Person } from "./Person";
2 |
3 | export function People() {
4 | return (
5 | <>
6 | People
7 | Get people
8 | No people to show
9 |
10 | >
11 | )
12 | }
--------------------------------------------------------------------------------
/03_creating_a_react_component/src/Person.jsx:
--------------------------------------------------------------------------------
1 | export const Person = () => {
2 | return (
3 | <>
4 | Person
5 | >
6 | );
7 | }
--------------------------------------------------------------------------------
/03_creating_a_react_component/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 |
5 | ReactDOM.createRoot(document.getElementById('root')).render(
6 |
7 |
8 | ,
9 | )
10 |
--------------------------------------------------------------------------------
/03_creating_a_react_component/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/04_JSX/.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 |
--------------------------------------------------------------------------------
/04_JSX/.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 |
--------------------------------------------------------------------------------
/04_JSX/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/04_JSX/README.md
--------------------------------------------------------------------------------
/04_JSX/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/04_JSX/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "react": "^18.3.1",
14 | "react-dom": "^18.3.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.3.3",
18 | "@types/react-dom": "^18.3.0",
19 | "@vitejs/plugin-react-swc": "^3.3.2",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/04_JSX/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { People } from "./People"
2 |
3 | function App() {
4 | const people = [
5 | { id: 0, name: { first: "Chandler", last: "Bing" } },
6 | { id: 1, name: { first: "Monica", last: "Geller" } },
7 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
8 | { id: 3, name: { first: "Rachel", last: "Green" } },
9 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
10 | ];
11 | return (
12 | <>
13 |
15 |
16 | Get people
17 | {people ? : No people to show
}
18 |
19 |
20 | Copyright © Us.com {(new Date()).getFullYear()}
21 |
22 | >
23 | )
24 | }
25 |
26 | export default App
27 |
--------------------------------------------------------------------------------
/04_JSX/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 |
4 | export function People({ people }) {
5 | return (
6 | <>
7 | People
8 | {people.map(person => {person.name.first} {person.name.last}
)}
9 |
10 | >
11 | )
12 | }
--------------------------------------------------------------------------------
/04_JSX/src/Person.jsx:
--------------------------------------------------------------------------------
1 | export const Person = () => {
2 | return (
3 | <>
4 | Person
5 | >
6 | );
7 | }
--------------------------------------------------------------------------------
/04_JSX/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 |
5 | ReactDOM.createRoot(document.getElementById('root')).render(
6 |
7 |
8 | ,
9 | )
10 |
--------------------------------------------------------------------------------
/04_JSX/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/05_events/.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 |
--------------------------------------------------------------------------------
/05_events/.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 |
--------------------------------------------------------------------------------
/05_events/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/05_events/README.md
--------------------------------------------------------------------------------
/05_events/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/05_events/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "react": "^18.3.1",
14 | "react-dom": "^18.3.1"
15 | },
16 | "devDependencies": {
17 | "@types/react": "^18.3.3",
18 | "@types/react-dom": "^18.3.0",
19 | "@vitejs/plugin-react-swc": "^3.3.2",
20 | "eslint": "^8.45.0",
21 | "eslint-plugin-react": "^7.32.2",
22 | "eslint-plugin-react-hooks": "^4.6.0",
23 | "eslint-plugin-react-refresh": "^0.4.3",
24 | "vite": "^4.4.5"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/05_events/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { People } from "./People"
2 |
3 | function App() {
4 | const people = [
5 | { id: 0, name: { first: "Chandler", last: "Bing" } },
6 | { id: 1, name: { first: "Monica", last: "Geller" } },
7 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
8 | { id: 3, name: { first: "Rachel", last: "Green" } },
9 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
10 | ];
11 | const numberToFetch = 10;
12 | const gender = "all";
13 | return (
14 | <>
15 |
17 |
18 |
32 | fetchPeople(numberToFetch, gender)}>Get people
33 | {people ? : No people to show
}
34 |
35 |
36 | Copyright © Us.com {(new Date()).getFullYear()}
37 |
38 | >
39 | )
40 |
41 | function fetchPeople(numberToFetch, gender) {
42 | const url = `https://randomuser.me/api/?results=${numberToFetch}&gender=${gender}&seed=42`
43 | fetch(url)
44 | .then(res => res.json())
45 | .then(res => res.results)
46 | .then(people => console.log("People", people))
47 | .catch(err => console.error("Error fetching", err))
48 | }
49 | }
50 |
51 | export default App
52 |
--------------------------------------------------------------------------------
/05_events/src/People.css:
--------------------------------------------------------------------------------
1 | .People {}
--------------------------------------------------------------------------------
/05_events/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 | import './People.css'
4 |
5 | export function People({ people }) {
6 | return (
7 |
8 | People
9 |
10 | {people.map(person => {person.name.first} {person.name.last}
)}
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | const styles = {
18 | wrapper: {
19 | display: "grid",
20 | gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
21 | }
22 | }
--------------------------------------------------------------------------------
/05_events/src/Person.jsx:
--------------------------------------------------------------------------------
1 | export const Person = () => {
2 | return (
3 | <>
4 | Person
5 | >
6 | );
7 | }
--------------------------------------------------------------------------------
/05_events/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 |
5 | ReactDOM.createRoot(document.getElementById('root')).render(
6 |
7 |
8 | ,
9 | )
10 |
--------------------------------------------------------------------------------
/05_events/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/06_styling/.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 |
--------------------------------------------------------------------------------
/06_styling/.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 |
--------------------------------------------------------------------------------
/06_styling/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/06_styling/README.md
--------------------------------------------------------------------------------
/06_styling/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/06_styling/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "bootstrap": "^5.3.3",
14 | "react": "^18.3.1",
15 | "react-dom": "^18.3.1"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.3.3",
19 | "@types/react-dom": "^18.3.0",
20 | "@vitejs/plugin-react-swc": "^3.3.2",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/06_styling/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { People } from "./People"
2 |
3 | function App() {
4 | const people = [
5 | { id: 0, name: { first: "Chandler", last: "Bing" } },
6 | { id: 1, name: { first: "Monica", last: "Geller" } },
7 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
8 | { id: 3, name: { first: "Rachel", last: "Green" } },
9 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
10 | ];
11 | const numberToFetch = 100;
12 | const gender = "all";
13 | return (
14 | <>
15 |
17 |
18 |
32 | fetchPeople(numberToFetch, gender)}>Get people
33 | {people ? : No people to show
}
34 |
35 |
36 | Copyright © Us.com {(new Date()).getFullYear()}
37 |
38 | >
39 | )
40 |
41 | function fetchPeople(numberToFetch, gender) {
42 | const url = `https://randomuser.me/api/?results=${numberToFetch}&gender=${gender}`
43 | fetch(url)
44 | .then(res => res.json())
45 | .then(res => res.results)
46 | .then(people => console.log("People", people))
47 | .catch(err => console.error("Error fetching", err))
48 | }
49 |
50 | }
51 |
52 | export default App
53 |
--------------------------------------------------------------------------------
/06_styling/src/People.css:
--------------------------------------------------------------------------------
1 | .People {}
--------------------------------------------------------------------------------
/06_styling/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 | import './People.css'
4 |
5 | export function People({ people }) {
6 | return (
7 |
8 | People
9 |
10 | {people.map(person => {person.name.first} {person.name.last}
)}
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | const styles = {
18 | wrapper: {
19 | display: "grid",
20 | gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
21 | }
22 | }
--------------------------------------------------------------------------------
/06_styling/src/Person.jsx:
--------------------------------------------------------------------------------
1 | export const Person = () => {
2 | return (
3 | <>
4 | Person
5 | >
6 | );
7 | }
--------------------------------------------------------------------------------
/06_styling/src/main.css:
--------------------------------------------------------------------------------
1 | :root {}
--------------------------------------------------------------------------------
/06_styling/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './main.css'
5 | import 'bootstrap/dist/css/bootstrap.css'
6 |
7 | ReactDOM.createRoot(document.getElementById('root')).render(
8 |
9 |
10 | ,
11 | )
12 |
--------------------------------------------------------------------------------
/06_styling/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/07_state/.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 |
--------------------------------------------------------------------------------
/07_state/.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 |
--------------------------------------------------------------------------------
/07_state/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/07_state/README.md
--------------------------------------------------------------------------------
/07_state/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/07_state/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "bootstrap": "^5.3.3",
14 | "react": "^18.3.1",
15 | "react-dom": "^18.3.1"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.3.3",
19 | "@types/react-dom": "^18.3.0",
20 | "@vitejs/plugin-react-swc": "^3.3.2",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/07_state/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import { People } from "./People"
3 |
4 | function App() {
5 | const [people, setPeople] = useState([
6 | { id: 0, name: { first: "Chandler", last: "Bing" } },
7 | { id: 1, name: { first: "Monica", last: "Geller" } },
8 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
9 | { id: 3, name: { first: "Rachel", last: "Green" } },
10 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
11 | ]);
12 | const [numberToFetch, setNumberToFetch] = useState(10);
13 | const [gender, setGender] = useState("all");
14 | return (
15 | <>
16 |
18 |
19 |
33 | fetchPeople(numberToFetch, gender)}>Get people
34 | {people ? : No people to show
}
35 |
36 |
37 | Copyright © Us.com {(new Date()).getFullYear()}
38 |
39 | >
40 | )
41 |
42 | function fetchPeople(numberToFetch, gender) {
43 | const url = `https://randomuser.me/api/?results=${numberToFetch}&gender=${gender}`
44 | fetch(url)
45 | .then(res => res.json())
46 | .then(res => res.results)
47 | .then(people => people.map((p, i) => ({ ...p, id: i })))
48 | .then(people => setPeople(people))
49 | .catch(err => console.error("Error fetching", err))
50 | }
51 | }
52 |
53 | export default App
54 |
--------------------------------------------------------------------------------
/07_state/src/People.css:
--------------------------------------------------------------------------------
1 | .People {}
--------------------------------------------------------------------------------
/07_state/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 | import './People.css'
4 |
5 | export function People({ people }) {
6 | return (
7 |
8 | People
9 |
10 | {people.map(person => {person.name.first} {person.name.last}
)}
11 |
12 |
13 |
14 | )
15 | }
16 |
17 | const styles = {
18 | wrapper: {
19 | display: "grid",
20 | gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
21 | }
22 | }
--------------------------------------------------------------------------------
/07_state/src/Person.jsx:
--------------------------------------------------------------------------------
1 | export const Person = () => {
2 | return (
3 | <>
4 | Person
5 | >
6 | );
7 | }
--------------------------------------------------------------------------------
/07_state/src/main.css:
--------------------------------------------------------------------------------
1 | :root {}
--------------------------------------------------------------------------------
/07_state/src/main.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import ReactDOM from 'react-dom/client'
3 | import App from './App.jsx'
4 | import './main.css'
5 | import 'bootstrap/dist/css/bootstrap.css'
6 |
7 | ReactDOM.createRoot(document.getElementById('root')).render(
8 |
9 |
10 | ,
11 | )
12 |
--------------------------------------------------------------------------------
/07_state/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/08_props/.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 |
--------------------------------------------------------------------------------
/08_props/.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 |
--------------------------------------------------------------------------------
/08_props/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/08_props/README.md
--------------------------------------------------------------------------------
/08_props/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/08_props/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "bootstrap": "^5.3.3",
14 | "react": "^18.3.1",
15 | "react-dom": "^18.3.1"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.3.3",
19 | "@types/react-dom": "^18.3.0",
20 | "@vitejs/plugin-react-swc": "^3.3.2",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/08_props/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import { People } from "./People"
3 |
4 | function App() {
5 | const [people, setPeople] = useState([
6 | { id: 0, name: { first: "Chandler", last: "Bing" } },
7 | { id: 1, name: { first: "Monica", last: "Geller" } },
8 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
9 | { id: 3, name: { first: "Rachel", last: "Green" } },
10 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
11 | ]);
12 | const [numberToFetch, setNumberToFetch] = useState(10);
13 | const [gender, setGender] = useState("all");
14 | return (
15 | <>
16 |
18 |
19 |
33 | fetchPeople(numberToFetch, gender)}>Get people
34 | {people ? : No people to show
}
35 |
36 |
37 | Copyright © Us.com {(new Date()).getFullYear()}
38 |
39 | >
40 | )
41 |
42 | function fetchPeople(numberToFetch, gender) {
43 | const url = `https://randomuser.me/api/?results=${numberToFetch}&gender=${gender}`
44 | fetch(url)
45 | .then(res => res.json())
46 | .then(res => res.results)
47 | .then(people => people.map((p, i) => ({ ...p, id: i })))
48 | .then(people => setPeople(people))
49 | .catch(err => console.error("Error fetching", err))
50 | }
51 | }
52 |
53 | export default App
54 |
--------------------------------------------------------------------------------
/08_props/src/People.css:
--------------------------------------------------------------------------------
1 | .People {}
--------------------------------------------------------------------------------
/08_props/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 | import './People.css'
4 |
5 | export function People({ people }) {
6 | return (
7 |
8 | People
9 |
10 | {people.map(person => )}
11 |
12 |
13 | )
14 | }
15 |
16 | const styles = {
17 | wrapper: {
18 | display: "grid",
19 | gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
20 | }
21 | }
--------------------------------------------------------------------------------
/08_props/src/Person.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | export const Person = ({ first, last, email, cell, imageSrc }) => {
3 | console.log(first, last, email, cell, imageSrc)
4 | return (
5 | <>
6 | Person
7 | >
8 | );
9 | }
--------------------------------------------------------------------------------
/08_props/src/main.css:
--------------------------------------------------------------------------------
1 | :root {}
--------------------------------------------------------------------------------
/08_props/src/main.jsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client'
2 | import App from './App.jsx'
3 | import './main.css'
4 | import 'bootstrap/dist/css/bootstrap.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/08_props/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/09_composition/.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 |
--------------------------------------------------------------------------------
/09_composition/.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 |
--------------------------------------------------------------------------------
/09_composition/README.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rapPayne/hands_on_react/ed0851d208e52c46463fe9dcd8a71faf6c84cead/09_composition/README.md
--------------------------------------------------------------------------------
/09_composition/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/09_composition/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "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 | "bootstrap": "^5.3.3",
14 | "react": "^18.3.1",
15 | "react-dom": "^18.3.1"
16 | },
17 | "devDependencies": {
18 | "@types/react": "^18.3.3",
19 | "@types/react-dom": "^18.3.0",
20 | "@vitejs/plugin-react-swc": "^3.3.2",
21 | "eslint": "^8.45.0",
22 | "eslint-plugin-react": "^7.32.2",
23 | "eslint-plugin-react-hooks": "^4.6.0",
24 | "eslint-plugin-react-refresh": "^0.4.3",
25 | "vite": "^4.4.5"
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/09_composition/src/App.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 | import { People } from "./People"
3 | import { PeopleQuery } from './PeopleQuery';
4 |
5 | function App() {
6 | const [people, setPeople] = useState([
7 | { id: 0, name: { first: "Chandler", last: "Bing" } },
8 | { id: 1, name: { first: "Monica", last: "Geller" } },
9 | { id: 2, name: { first: "Phoebe", last: "Buffay" } },
10 | { id: 3, name: { first: "Rachel", last: "Green" } },
11 | { id: 4, name: { first: "Joey", last: "Tribiani" } },
12 | ]);
13 | const [numberToFetch, setNumberToFetch] = useState(10);
14 | const [gender, setGender] = useState("all");
15 | return (
16 | <>
17 |
19 |
20 |
21 | {people ? : No people to show
}
22 |
23 |
24 | Copyright © Us.com {(new Date()).getFullYear()}
25 |
26 | >
27 | )
28 |
29 | function fetchPeople(numberToFetch, gender) {
30 | const url = `https://randomuser.me/api/?results=${numberToFetch}&gender=${gender}`
31 | fetch(url)
32 | .then(res => res.json())
33 | .then(res => res.results)
34 | .then(people => people.map((p, i) => ({ ...p, id: i })))
35 | .then(people => setPeople(people))
36 | .catch(err => console.error("Error fetching", err))
37 | }
38 | }
39 |
40 | export default App
41 |
--------------------------------------------------------------------------------
/09_composition/src/People.css:
--------------------------------------------------------------------------------
1 | .People {}
--------------------------------------------------------------------------------
/09_composition/src/People.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import { Person } from "./Person";
3 | import './People.css'
4 |
5 | export function People({ people }) {
6 | return (
7 |
8 | People
9 |
10 | {people.map(person => )}
11 |
12 |
13 | )
14 | }
15 |
16 | const styles = {
17 | wrapper: {
18 | display: "grid",
19 | gridTemplateColumns: "repeat(auto-fit, minmax(250px, 1fr))",
20 | }
21 | }
--------------------------------------------------------------------------------
/09_composition/src/PeopleQuery.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 |
3 | export const PeopleQuery = ({ gender, setGender, numberToFetch, setNumberToFetch, fetchPeople }) => {
4 | return (
5 |
20 | )
21 | }
--------------------------------------------------------------------------------
/09_composition/src/Person.css:
--------------------------------------------------------------------------------
1 | .Person {
2 | background-color: bisque;
3 | margin: 10px;
4 |
5 | &>h2 {
6 | text-align: center;
7 | }
8 |
9 | &>img {
10 | width: 100%;
11 | border-radius: 50%;
12 | }
13 |
14 | &>p {
15 | padding: 0 10px;
16 | margin: 0;
17 | overflow: hidden;
18 |
19 | &>span:first-child {
20 | font-weight: bold;
21 | padding-right: 5px;
22 | }
23 |
24 | &>span {}
25 | }
26 | }
--------------------------------------------------------------------------------
/09_composition/src/Person.jsx:
--------------------------------------------------------------------------------
1 | /* eslint-disable react/prop-types */
2 | import "./Person.css";
3 |
4 | export const Person = ({ first, last, email, cell, imageSrc }) => {
5 | // console.log(first, last, email, cell, imageSrc)
6 | return (
7 |
8 | {first} {last}
9 |
10 | Email: {email}
11 | Cell: {cell}
12 |
13 | );
14 | }
--------------------------------------------------------------------------------
/09_composition/src/main.css:
--------------------------------------------------------------------------------
1 | :root {}
--------------------------------------------------------------------------------
/09_composition/src/main.jsx:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom/client'
2 | import App from './App.jsx'
3 | import './main.css'
4 | import 'bootstrap/dist/css/bootstrap.css'
5 |
6 | ReactDOM.createRoot(document.getElementById('root')).render(
7 |
8 | )
9 |
--------------------------------------------------------------------------------
/09_composition/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react-swc'
3 |
4 | // https://vitejs.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Rap Payne
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # hands_on_react
2 | To support my Hands On React course on O'Reilly Learning Portal
3 |
4 | # Connect with Rap
5 | I'd love to connect with you to provide help learning React. Please reach out.
6 | - X: [@RapPayne](https://X.com/RapPayne)
7 | - LinkedIn: [RapPayne](https://www.linkedin.com/in/rappayne/)
8 | - Github: [RapPayne](https://github.com/rapPayne)
9 | - Web: AgileGadgets.com
10 |
11 | We've created solutions at certain checkpoints.
12 | 1. [Create a React app](02_create_a_react_app)
13 | 2. [Creating a React component](03_creating_a_react_component)
14 | 1. [JSX](04_JSX)
15 | 1. [Events](05_events)
16 | 1. [Styling](06_styling)
17 | 1. [State](07_state)
18 | 5. [Props](08_props)
19 | 1. [Composition](09_composition)
20 |
21 | ## How to run these examples
22 | 1. cd to the folder of your choice
23 | 3. npm install
24 | 4. npm run dev
25 |
26 | Of course you can make any changes to the code you like at this point. Just save a file and the app will refresh in your browser.
27 |
28 | ## Exercises
29 | (No exercise for section 1 - Intro to React).
30 |
31 | ### 2. Create a React app
32 | This one is simple. Just `npm create vite` to create the application.
33 |
34 | ### 3. Creating a React component
35 | 1. Make two component files: People.jsx and Person.jsx.
36 | 2. Add the data-reading code to People.jsx. If you like, you can copy the fetcher from assets/fetchPeople.js.
37 |
38 | ### 4. JSX
39 | Now, drawing the people in App.js doesn't seem clean. We should be drawing the people in People.js. But we have to get those people into PeopleList somehow. Props will do the trick!
40 | 3. Add JSX to App.jsx to host People.js.
41 | 4. Add JSX to People.js to host Person.js.
42 | 5. Add a button to People.js to fetch 10 people. Console.log() them.
43 |
44 | ### 5. Events
45 | 1. Make the delete button call your new deletePerson function
46 |
47 | ### 6. Styling
48 | 1. Add in CSS to format the Person. Put this in Person.css and import it.
49 | 2. Use JavaScript styles for the flexbox layout.
50 |
51 | ### 7. State
52 | 1. In People, add a function to delete a single person from the people list. Make it call setState() with the new list of people.
53 | 1. Add a delete button to each Person.
54 | 1. Pass the function from People into Person via a prop.
55 | 1. Make the delete button call your new deletePerson function
56 |
57 | ### 8. Props
58 | Now, drawing the people in App.js doesn't seem clean. We should be drawing the people in People.js. But we have to get those people into PeopleList somehow. Props will do the trick!
59 | 1. Pass people from People.js down to Person.js
60 |
61 | ### 9. Composition
62 |
--------------------------------------------------------------------------------
/ReactCheatSheet.md:
--------------------------------------------------------------------------------
1 | # Quick ref - JavaScript things you commonly need for React
2 |
3 | ## Destructuring
4 | ```JavaScript
5 | const array = ['one', 'two', 'three', 'four'];
6 | const object = { id: 123, name: 'Jo', email: 'jo@gmail.com' };
7 | ```
8 |
9 | ```JavaScript
10 | const [first, second, , , last ] = array;
11 |
12 | ```
13 | // or
14 | let {first, last} = {
15 | first: 'Cyan',
16 | last: 'Hall'
17 | }
18 |
19 | ## Ways to create a function
20 | const getName = user => user.name
21 | const funcName = name => {
22 | // do something
23 | return name
24 | }
25 |
26 | ## Arrays
27 | // Delete at index
28 | array.splice(index, 1)
29 |
30 | // Insert at index
31 | array.splice(index, 0, newItem)
32 |
33 | // check exist
34 | [1, 2, 3].includes(3) // true
35 |
36 | // find index
37 | [1, 2, 3].indexOf(3) // 2; return -1 if not found
38 |
39 | // concat
40 | let array3 = array1.concat(array2) // [1].concat([2]) is [1, 2]
41 |
42 | // new array
43 | let array4 = [1, 2, 3, 4, 5].slice(2, 4) // [3, 4]
44 |
45 | ## Iterating arrays
46 | for (const i of [1, 2, 3]) {
47 | console.log(i)
48 | }
49 | // 1
50 | // 2
51 | // 3
52 |
53 | for (const [index, value] of ['Cyan', 'Hall', '.com'].entries()) {
54 | console.log(index, value)
55 | }
56 | // 0 "Cyan"
57 | // 1 "Hall"
58 | // 2 ".com"
59 |
60 | const obj = {part1: 'Cyan', part2: 'Hall', part3: '.com'};
61 | for (const key in obj) {
62 | console.log(key, obj[key])
63 | }
64 | // or
65 | for (const [key, value] of Object.entries(obj)) {
66 | console.log(key, value)
67 | }
68 | // part1 Cyan
69 | // part2 Hall
70 | // part3 .com
71 |
72 | ### But you may not need to iterate
73 | const numbers = [1, 2, 3]
74 | numbers.map(n => n * 2) // [2, 4, 6]
75 | numbers.filter(n => n % 2 === 0) // [2]
76 | numbers.reduce((prev, next) => prev + next, 0) // 6
77 | numbers.find(n => n > 2) // 3
78 |
79 | ## Async
80 | funcName('test')
81 | .then(result => {
82 | // ...
83 | })
84 | .catch(error => {
85 | // ...
86 | })
87 | .finally(() => {
88 | // ...
89 | })
90 |
91 | ## async/await
92 | const funcName = async () => {
93 | const data = await fetchData()
94 | return data
95 | }
96 |
97 | await funcName()
98 |
99 | ## Spread
100 | const options = {
101 | ...defaults,
102 | show: true
103 | }
104 |
105 | const array3 = [
106 | ...array1,
107 | ...array2,
108 | 'newItem'
109 | ]
110 |
111 | ## Template strings
112 | let text = ( `cat
113 | dog
114 | nickelodeon`
115 | );
116 | Template Literals can accept expressions, as well:
117 |
118 | let today = new Date();
119 | let text = `The time and date is ${today.toLocaleString()}`;
120 |
121 | ## Modules
122 | To share JS from another file we need two things:
123 | 1. To export from one file
124 | 2. To import from the other
125 |
126 | file1.js
127 | ```JavaScript
128 | export let name = 'Jo'; // "named" export
129 | let age = 27;
130 | export default age; // "default" export
131 | ```
132 |
133 | file2.js
134 | ```JavaScript
135 | import age from './file1.js'; // default import
136 | import { name } from './file1.js'; // named import
137 | ```
138 |
--------------------------------------------------------------------------------
/assets/Person.css:
--------------------------------------------------------------------------------
1 | .Person {
2 | background-color: var(--secondary);
3 | flex: 1 1 100px;
4 | margin: 10px;
5 |
6 | & div.imageAndName {
7 | position: relative;
8 |
9 | & img {
10 | width: 100%;
11 | position: relative;
12 | }
13 |
14 | & p {
15 | position: absolute;
16 | top: 0;
17 | padding: 5px;
18 | margin: 0;
19 | font-size: 1.5em;
20 | width: 100%;
21 | text-align: center;
22 | background: linear-gradient(var(--background), rgba(255, 255, 255, 0));
23 | }
24 | }
25 |
26 | & div.details {
27 | & div {
28 | & p {
29 | margin: 0 10px 0 10px;
30 | padding: 0;
31 | }
32 |
33 | & p:first-of-type {
34 | text-transform: uppercase;
35 | font-weight: bold;
36 |
37 | & ::after {
38 | content: ":";
39 | }
40 | }
41 |
42 | & p:last-of-type {}
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/assets/Person.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
{person?.name.first} {person?.name.last}
5 |
6 |
7 |
8 |
9 |
10 | Cell
11 | {person?.cell}
12 |
13 |
14 | Email
15 | {person?.email}
16 |
17 |
18 | Address
19 |
20 | {person?.location.street.number} {person?.location.street.name}
21 | {person?.location?.city},
22 | {person?.location?.state}
23 | {person?.location?.postcode}
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/assets/README.md:
--------------------------------------------------------------------------------
1 | ### Assets
2 | This folder contains pre-written code and other things to make the creation of your React app simpler.
3 |
4 |
--------------------------------------------------------------------------------
/assets/fetchPeople.js:
--------------------------------------------------------------------------------
1 | export function fetchPeople(number=10, nat=['gb','fi', 'de', 'us'], gender="all") {
2 | const url=`https://randomuser.me/api/?results=${number}&nat=${nat.join(",")}&gender=${gender}`;
3 | console.log(url);
4 | return fetch(url)
5 | .then(res => res.json())
6 | .then(res => res.results)
7 | .catch(err => console.error("Error fetching people", err));
8 | }
--------------------------------------------------------------------------------