├── .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 ? : 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 | }; --------------------------------------------------------------------------------