├── .babelrc
├── .gitignore
├── Readme.md
├── package-lock.json
├── package.json
├── src
├── App.js
├── Button.js
├── ButtonWithTooltip.js
├── Heading.js
├── Input.js
├── Navbar.js
├── PrintTable.js
├── SecondParent.js
├── Text.js
├── ThirdParent.js
├── Timer.js
├── Tooltip.js
├── app.module.css
├── context.js
├── counterSlice.js
├── index.html
├── index.js
├── input.css
├── store.js
└── styles.css
└── webpack.config.js
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react"]
3 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## Curricullum of the course :
2 |
3 | 1. Brief introduction of react
4 | 2. Using react via CDN
5 | 3. Setup react app via Webpack
6 | 4. Module 4
7 | - Introduction to JSX
8 | - Element vs Component
9 | - Conditional rendering
10 | 5. Module 5
11 | - Intro to props and children
12 | - What are import, and export terminologies
13 | 6. Module 6
14 | - How to render data from lists
15 | - Importance of keys prop
16 | 7. Module 7
17 | - What are hooks
18 | - Understanding useState
19 | - What is re-render
20 | - Misuse of state variables
21 | 8. What is React Fiber and Reconciliation
22 | 9. Exploring UseEffect hook
23 | 10. All about useLayoutEffect
24 | 11. Module 11
25 | - All about useRef Hook
26 | - forwardRef API
27 | 12. All about useCallback
28 | 13. All about useMemo Hook
29 | 14. Understanding Memo API
30 | 15. React Optimization via Lazy API and Suspense Component
31 | 16. React createContext API and useContext hook
32 | 17. Introduction to createPortal in react-dom
33 | 18. Introduction to Redux and Redux-toolkit
34 | 19. Introduction to React Router
35 | 20. What are React Design Patterns?
36 | 21. React HOC (Higher Order Component) Design Pattern
37 | 22. React Render Props Pattern
38 | 23. React Composition or Compound Pattern
39 | 24. React Custom Hook Pattern
40 | 25. How to fetch data from an API and Image Optimizations
41 | 26. Dealing with input form and optimizations
42 | 27. How to style components in React
43 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "complete-react-tutorial",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "serve": "webpack serve --mode development",
9 | "build": "webpack --mode production"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "@reduxjs/toolkit": "^1.9.7",
15 | "lodash": "^4.17.21",
16 | "react": "^18.2.0",
17 | "react-dom": "^18.2.0",
18 | "react-redux": "^8.1.3",
19 | "react-router-dom": "^6.17.0"
20 | },
21 | "devDependencies": {
22 | "@babel/core": "^7.23.0",
23 | "@babel/preset-env": "^7.22.20",
24 | "@babel/preset-react": "^7.22.15",
25 | "babel-loader": "^9.1.3",
26 | "css-loader": "^6.8.1",
27 | "html-webpack-plugin": "^5.5.3",
28 | "sass": "^1.69.0",
29 | "sass-loader": "^13.3.2",
30 | "style-loader": "^3.3.3",
31 | "url-loader": "^4.1.1",
32 | "webpack": "^5.88.2",
33 | "webpack-cli": "^5.1.4",
34 | "webpack-dev-server": "^4.15.1"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, {useEffect, useMemo, useState} from 'react';
2 | import { debounce } from 'lodash';
3 |
4 | import styles from './app.module.css'
5 | import './input.css'
6 |
7 | const App = () => {
8 | const [inputData, setInputData] = useState('')
9 | const [data, setData] = useState()
10 |
11 | const debouncedFetchData = useMemo(() => debounce(async (searchString) => {
12 | const response = await fetch(`https://swapi.dev/api/people/?search=${searchString}`)
13 | const data = await response.json()
14 | console.log(data)
15 | setData(data?.results)
16 | }, 300), [])
17 |
18 | const handleInputChange = (e) => {
19 | const value = e?.target?.value
20 | setInputData(value)
21 | debouncedFetchData(value)
22 | }
23 |
24 | useEffect(() => {
25 | return () => {
26 | debouncedFetchData?.cancel()
27 | }
28 | }, [])
29 |
30 | return <>
31 |
Welcome to Star Wars
32 |
33 |
34 | {data && data?.length ?
35 | {data.map((item) => - {item?.name}
)}
36 |
: Loading}
37 | >
38 | }
39 |
40 | export default App
--------------------------------------------------------------------------------
/src/Button.js:
--------------------------------------------------------------------------------
1 | import React, {memo, useContext} from 'react';
2 | import { ThemeContext } from './context';
3 | const Button = memo((props) => {
4 | const {children, clickAction} = props
5 | const [theme, setTheme] = useContext(ThemeContext)
6 | const handleClick = () => {
7 | clickAction?.()
8 | setTheme((prev) => {
9 | return prev === 'dark' ? 'light' : 'dark'
10 | })
11 | }
12 | return
15 | })
16 |
17 | export default Button;
--------------------------------------------------------------------------------
/src/ButtonWithTooltip.js:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect, useLayoutEffect, useRef} from 'react';
2 |
3 | import Tooltip from './Tooltip'
4 | const ButtonWithTooltip = (props) => {
5 | const {tooltipContent, children} = props
6 | const [targetPositions, setPositions] = useState(null)
7 | const buttonRef = useRef(null)
8 | const handleMouseEnter = () => {
9 | const rect = buttonRef.current.getBoundingClientRect();
10 | setPositions({
11 | left: rect.left,
12 | top: rect.top,
13 | right: rect.right,
14 | bottom: rect.bottom,
15 | })
16 | }
17 | return <>
18 |
25 | {targetPositions && {tooltipContent}}
26 | >
27 | }
28 |
29 | export default ButtonWithTooltip;
--------------------------------------------------------------------------------
/src/Heading.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import Text from './Text'
4 | const Heading = (props) => {
5 | const {headingText} = props
6 | console.log("heading re-render")
7 | return <>
8 | hey I am heading component
9 | Hey i am text component
10 | >
11 | }
12 |
13 |
14 | export default Heading
--------------------------------------------------------------------------------
/src/Input.js:
--------------------------------------------------------------------------------
1 | import React, {forwardRef } from 'react';
2 | const Input = forwardRef((props, ref) => {
3 | console.log("input box props are: ", props)
4 | return
5 | })
6 |
7 | export default Input
--------------------------------------------------------------------------------
/src/Navbar.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Button from './Button'
3 | const Navbar = () => {
4 | return <>
5 | Home
6 | About US
7 |
8 | >
9 | }
10 |
11 | export default Navbar
--------------------------------------------------------------------------------
/src/PrintTable.js:
--------------------------------------------------------------------------------
1 | import React, {useMemo, memo} from 'react';
2 | const generateTable = (number) => {
3 | const arr = []
4 | let startTime = performance.now();
5 | while (performance.now() - startTime < 800) {
6 | // Do nothing for 500 ms to emulate extremely slow code
7 | }
8 | for (let i = 1; i <= 10; i++) {
9 | arr.push({number * i}
)
10 | }
11 | return arr
12 | }
13 |
14 | const PrintTable = memo((props) => {
15 | const {num, obj, val, arr} = props
16 | // const table = useMemo(() => generateTable(num), [num])
17 | const table = generateTable(num)
18 | console.log(table)
19 | return <>
20 | {table}
21 | {obj?.channel}
22 |
23 | {val}
24 |
25 | {arr?.map((item) => {item})}
26 | >
27 | })
28 |
29 | export default PrintTable;
--------------------------------------------------------------------------------
/src/SecondParent.js:
--------------------------------------------------------------------------------
1 | import React, { useCallback } from 'react';
2 | import ThirdParent from './ThirdParent';
3 | const SecondParent = () => {
4 | const myFunction = useCallback(() => {
5 | console.log("my function called")
6 | }, [])
7 | const handleChange = useCallback(() => {
8 | console.log("hey hey haha")
9 | myFunction()
10 | }, [myFunction])
11 |
12 | return <>
13 | I am second parent
14 |
15 |
16 | >
17 | }
18 |
19 | export default SecondParent;
20 |
21 |
--------------------------------------------------------------------------------
/src/Text.js:
--------------------------------------------------------------------------------
1 | import React, {memo, useEffect} from 'react';
2 |
3 | const Text = memo((props) => {
4 | const {externalData, children} = props
5 |
6 | useEffect(() => {
7 | console.log("External Data changed ", externalData)
8 | }, [externalData])
9 | return {externalData}{children}
10 | })
11 |
12 | export default Text
--------------------------------------------------------------------------------
/src/ThirdParent.js:
--------------------------------------------------------------------------------
1 | import React, { useState, memo, useCallback } from "react"
2 |
3 | const ThirdParent = memo((props) => {
4 | const {handleChange} = props;
5 | const [counter, setCounter] = useState(0)
6 |
7 | let startTime = performance.now();
8 | while (performance.now() - startTime < 800) {
9 | // Do nothing for 500 ms to emulate extremely slow code
10 | }
11 | const increment = useCallback(() => {
12 | setCounter((prev) => prev + 1)
13 | handleChange?.()
14 | }, [])
15 | return <>
16 | I am a super super slow component
17 |
18 | {counter}
19 | >
20 | })
21 |
22 | export default ThirdParent;
--------------------------------------------------------------------------------
/src/Timer.js:
--------------------------------------------------------------------------------
1 | import React, {useState, useEffect, useRef} from 'react';
2 | const Timer = (props) => {
3 | const {customText} = props
4 | const [counter, setCounter] = useState(0)
5 | const interval = useRef(null)
6 |
7 | useEffect(() => {
8 | interval.current = setInterval(() => {
9 | console.log("I am running setInterval")
10 | setCounter((prevCounter) => prevCounter + 1)
11 | }, 1000)
12 | return () => {
13 | clearInterval(interval.current)
14 | }
15 |
16 | }, [])
17 |
18 | const stopTimer = () => {
19 | console.log("stopping timer for id ", interval.current)
20 | clearInterval(interval.current)
21 | }
22 |
23 | return <>
24 | Current time is: {counter}
25 |
26 | {customText}
27 |
28 |
29 | >
30 | }
31 |
32 | export default Timer;
--------------------------------------------------------------------------------
/src/Tooltip.js:
--------------------------------------------------------------------------------
1 | import React, {useRef, useState, useEffect, useLayoutEffect} from 'react';
2 | import {createPortal} from 'react-dom';
3 | const Tooltip = (props) => {
4 | const {children, targetPositions} = props
5 | const {left, top, right, bottom} = targetPositions
6 | const tooltipRef = useRef(null)
7 | const [tooltipHeight, setTooltipHeight] = useState(0);
8 |
9 | let x = 0
10 | let y = 0
11 |
12 | let now = performance.now();
13 | while (performance.now() - now < 400) {
14 | // render blocking code
15 | }
16 |
17 | if (targetPositions !== null) {
18 | x = left
19 | y = top - tooltipHeight
20 | console.log("the height is", tooltipHeight)
21 | if (y < 0) {
22 | y = bottom
23 | }
24 | }
25 |
26 | useLayoutEffect(() => {
27 | const { height } = tooltipRef.current.getBoundingClientRect();
28 | setTooltipHeight(height)
29 | console.log("the height is inside effect", height)
30 | }, [])
31 |
32 | return createPortal(
39 | {children}
40 |
, document.body)
41 | }
42 |
43 | export default Tooltip;
--------------------------------------------------------------------------------
/src/app.module.css:
--------------------------------------------------------------------------------
1 | .inputElement {
2 | border: 1px solid green;
3 | padding: 10px;
4 | }
--------------------------------------------------------------------------------
/src/context.js:
--------------------------------------------------------------------------------
1 | import { createContext } from 'react';
2 |
3 | const ThemeContext = createContext('themeContext');
4 |
5 | export {ThemeContext};
--------------------------------------------------------------------------------
/src/counterSlice.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from '@reduxjs/toolkit'
2 |
3 | const initialState = {
4 | counterValue: 0,
5 | }
6 |
7 | export const counterSlice = createSlice({
8 | name: 'counter',
9 | initialState,
10 | reducers: {
11 | increment: (state) => {
12 | state.counterValue += 1
13 | },
14 | decrement: (state) => {
15 | state.counterValue -= 1
16 | },
17 | incByAmount: (state, action) => {
18 | console.log(state.counterValue)
19 | console.log(action)
20 | state.counterValue += action.payload
21 | }
22 | }
23 | })
24 |
25 | // Action creators are generated for each case reducer function
26 | export const { increment, decrement, incByAmount } = counterSlice.actions
27 |
28 | export default counterSlice.reducer
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Document
7 |
8 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom/client';
3 | import { BrowserRouter } from 'react-router-dom';
4 | import App from './App'
5 | import "./styles.css";
6 | import { Provider } from 'react-redux'
7 | import {store} from './store'
8 |
9 | const root = ReactDOM.createRoot(document.getElementById('root'))
10 | root.render(
11 |
12 |
13 |
14 |
15 |
16 | )
--------------------------------------------------------------------------------
/src/input.css:
--------------------------------------------------------------------------------
1 | .inputElement {
2 | border: 1px solid green;
3 | padding: 10px;
4 | }
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit'
2 | import counterReducer from './counterSlice'
3 | export const store = configureStore({
4 | reducer: {
5 | counter: counterReducer,
6 | },
7 | })
--------------------------------------------------------------------------------
/src/styles.css:
--------------------------------------------------------------------------------
1 | .tooltip {
2 | color: white;
3 | background: #222;
4 | border-radius: 4px;
5 | padding: 4px;
6 | }
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const HtmlWebpackPlugin = require("html-webpack-plugin");
3 |
4 | module.exports = {
5 | output: {
6 | path: path.join(__dirname, "/dist"), // the bundle output path
7 | filename: "bundle.js", // the name of the bundle
8 | },
9 | plugins: [
10 | new HtmlWebpackPlugin({
11 | template: "src/index.html", // to import index.html file inside index.js
12 | }),
13 | ],
14 | devServer: {
15 | port: 3000, // you can change the port,
16 | historyApiFallback: true,
17 | },
18 | module: {
19 | rules: [
20 | {
21 | test: /\.(js|jsx)$/, // .js and .jsx files
22 | exclude: /node_modules/, // excluding the node_modules folder
23 | use: {
24 | loader: "babel-loader",
25 | },
26 | },
27 | {
28 | test: /\.(sa|sc|c)ss$/, // styles files
29 | use: ["style-loader", "css-loader", "sass-loader"],
30 | },
31 | {
32 | test: /\.(png|woff|woff2|eot|ttf|svg)$/, // to import images and fonts
33 | loader: "url-loader",
34 | options: { limit: false },
35 | },
36 | ],
37 | },
38 | };
--------------------------------------------------------------------------------