# React Learning notes --- ## 1. React ### 1.1. Introduction - A frontend JavaScript **framework**, a JavaScript **library** for building UI (user interfaces) created by Facebook. - Used to build **SPA** (single-page applications) - a web app that **loads only a single web document**, and then **_updates_** the body content of that single document via JavaScript APIs such as Fetch **_when different content is to be shown_**. - Allows us to create reusable UI components. ### 1.2. Some key concepts - **Components**: The fundamental building blocks of a React application. A component is a **reusable** piece of code that **_encapsulates_** the **_HTML_**, **_CSS_**, and **_JavaScript_** code required to render a piece of the UI (_they can be simple UI elements like buttons or complex structures like entire pages._) - **Function Components**: A Javascript function that accepts **_props_** and returns a **React element** - JSX (JavaScript XML). - **Class Components**: A JavaScript class that extends **_React.Component_** and has a **_render_** method that returns a **React element** - JSX (JavaScript XML). - **JSX**: A syntax extension for JavaScript that looks similar to XML/HTML. It allows us to write HTML-like elements in JavaScript and place them in the DOM without using functions like **_createElement()_** or **_appendChild()_**. (You are not required to use JSX, but JSX makes it easier to write React applications.) ```jsx // Example of JSX const element = <h1>Hello, world!</h1>; ``` - **Props**: _Short for properties_, they are used to pass data from a parent component to a child component. They are **_read-only_** and **_immutable_**. ```jsx // Example of props function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="Sara" />; ``` - **State**: An object that holds some information that may change over the lifetime of the component. It is **_mutable_** and **_private_** to the component that owns it. **_When the state of a component changes, the component automatically re-renders_**. ```jsx // Example of state class Clock extends React.Component { constructor(props) { super(props); this.state = { date: new Date() }; } render() { return <h1>It is {this.state.date.toLocaleTimeString()}.</h1>; } } ``` - **Lifecycle Methods**: Methods that are **called automatically** by React **at specific points in the lifecycle of a component**. They are used to perform some actions when the component is created, updated, or destroyed. - `componentDidMount()`: Invoked immediately after a component is mounted (inserted into the tree). - `componentDidUpdate()`: Invoked immediately after updating occurs. - `componentWillUnmount()`: Invoked immediately before a component is unmounted and destroyed. - **Hooks** (from React 16.8): functions that let you **use state and other React features without writing a class**. They allow you to use state and other React features in functional components. - `useState()`: A hook that allows you to add state to a functional component. - `useEffect()`: A hook that allows you to perform side effects in functional components. - `useContext()`: A hook that allows you to use the context API in functional components. - `useReducer()`: A hook that allows you to manage state in functional components. - **Virtual DOM**: A lightweight copy of the actual DOM. React uses the virtual DOM to **_minimize the number of updates to the actual DOM_**. When the state of a component changes, React **updates the virtual DOM first**, then compares it with the actual DOM, and finally **updates only the parts of the actual DOM that have changed**. - **ES6** (React uses ES6): ECMAScript 6, also known as ES6 or ECMAScript 2015, is the latest version of the ECMAScript standard. It introduces many new features to JavaScript, such as **_arrow functions_**, **_classes_**, **_let_** and **_const_** declarations, **_template literals_**, **_destructuring_**, and **_spread syntax_**. ### 1.3. How React works **`React creates a VIRTUAL DOM in memory.`** **`React only changes what needs to be changed!`** - **React** creates a **virtual DOM** (in memory) that is a lightweight copy of the actual DOM and **_updates it first_**. - **React** then **compares** the virtual DOM with the actual DOM and **_updates only the parts of the actual DOM that have changed_**. #### React render HTML Use **createRoot()** function and its method render() to render a React element into the DOM. ```jsx const element = <h1>Hello, world!</h1>; const container = document.getElementById("root"); const root = ReactDOM.createRoot(container); root.render(element); ``` - The createRoot Function: Creates a new **Root** object that represents a **_React root_**. It accepts a container element as an argument. Purpose: define the HTML element where a React component should be rendered. - The render Method: Renders a React element into the DOM. It accepts a React element as an argument. Purpose: render a React element into the DOM. ### 1.4. Implementing React #### 1.4.1. React directly in HTML Using **_CDN links_** to include React in an HTML file. ```html <!-- React library --> <script src="https://unpkg.com/react@18/umd/react.development.js"></script> <!-- React DOM library --> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <!-- Babel, allows us to write JSX syntax and ES6 in older browsers. --> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> ``` ```html <!DOCTYPE html> <html> <head> <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin ></script> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> </head> <body> <div id="mydiv"></div> <script type="text/babel"> function Hello() { return <h1>Hello World!</h1>; } const container = document.getElementById("mydiv"); const root = ReactDOM.createRoot(container); root.render(<Hello />); </script> </body> </html> ``` _This way of using React can be OK for testing purposes, but for production you will need to set up a React environment._ #### 1.4.2. Create React App 1. Install **Node.js**. 2. Install **npx** (Node Package Runner) globally. ```bash npm install -g npx ``` 3. Create a new React app using **Create React App** named **my-app**. ```bash npx create-react-app my-app ``` 4. Change to the **my-app** directory and start the development server. ```bash cd my-app npm start ``` 5. Open the browser and navigate to **http://localhost:3000/**. ## 1.5. ES6 Features ### 1.5.1. Arrow Functions - Arrow functions are a more concise way to write functions in JavaScript. ```jsx // Traditional function function add(a, b) { return a + b; } // Arrow function const add = (a, b) => { a + b; }; // If the function has only one statement, you can omit the curly braces and the return keyword. const add = (a, b) => a + b; // If the function has only one parameter, you can omit the parentheses. const square = (x) => x * x; const square = (x) => x * x; ``` ### 1.5.2. Variable Declarations: var, let, and const - **var**: The variable declared with **var** is **_function-scoped_**. It means that the variable is available within the function in which it is declared. - **let**: The variable declared with **let** is **_block-scoped_**. It means that the variable is available within the block in which it is declared. - **const**: The variable declared with **const** is also **_block-scoped_**. It means that the variable is available within the block in which it is declared. The value of a **const** variable cannot be changed once it is assigned. ```jsx // var function varExample() { if (true) { var x = 10; } console.log(x); // 10 } // let function letExample() { if (true) { let x = 10; } console.log(x); // ReferenceError: x is not defined } // const const PI = 3.14; PI = 3.14159; // TypeError: Assignment to constant variable. ``` ### 1.5.3. Classes - A class is a type of function, but instead of using the keyword **_function_** to initiate it, we use the keyword **_class_**, and the properties are assigned inside a **_constructor()_** method. ```jsx class Car { constructor(brand) { this.carname = brand; } } mycar = new Car("Ford"); ``` - Methods can be added to a class using the **_class method_** syntax. ```jsx class Car { constructor(brand) { this.carname = brand; } present() { return "I have a " + this.carname; } } mycar = new Car("Ford"); mycar.present(); ``` - Class Inheritance: The **_extends_** keyword is used in class declarations or class expressions. ```jsx class Car { constructor(brand) { this.carname = brand; } present() { return "I have a " + this.carname; } } class Model extends Car { constructor(brand, mod) { super(brand); this.model = mod; } show() { return this.present() + ", it is a " + this.model; } } mycar = new Model("Ford", "Mustang"); mycar.show(); ``` ### 1.5.4. Array Methods `There are many JavaScript array methods. Some of the most commonly used array methods are:` - **map()**: Creates a new array with the results of calling a provided function on every element in the array. ```jsx const numbers = [1, 2, 3, 4, 5]; const doubled = numbers.map((number) => number * 2); console.log(doubled); // [2, 4, 6, 8, 10] ``` - **filter()**: Creates a new array with all elements that pass the test implemented by the provided function. ```jsx const numbers = [1, 2, 3, 4, 5]; const even = numbers.filter((number) => number % 2 === 0); console.log(even); // [2, 4] ``` - **reduce()**: Executes a reducer function on each element of the array, resulting in a single output value. ```jsx const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((total, number) => total + number, 0); console.log(sum); // 15 ``` - **forEach()**: Calls a function for each element in the array. ```jsx const numbers = [1, 2, 3, 4, 5]; numbers.forEach((number) => console.log(number)); ``` - **find()**: Returns the first element in the array that satisfies the provided testing function. ```jsx const numbers = [1, 2, 3, 4, 5]; const even = numbers.find((number) => number % 2 === 0); console.log(even); // 2 ``` - **some()**: Tests whether at least one element in the array passes the test implemented by the provided function. ```jsx const numbers = [1, 2, 3, 4, 5]; const even = numbers.some((number) => number % 2 === 0); console.log(even); // true ``` - **every()**: Tests whether all elements in the array pass the test implemented by the provided function. ```jsx const numbers = [1, 2, 3, 4, 5]; const even = numbers.every((number) => number % 2 === 0); console.log(even); // false ``` ### 1.5.5. Destructuring - Destructuring is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. ```jsx // Array Destructuring const numbers = [1, 2, 3]; const [a, b, c] = numbers; console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 // Object Destructuring const person = { name: "John", age: 30 }; const { name, age } = person; console.log(name); // John console.log(age); // 30 ``` ### 1.5.6. Spread Operator (...) - The spread operator is used to **expand** an **iterable** object into its individual elements. ```jsx const numbers = [1, 2, 3]; const newNumbers = [...numbers, 4, 5]; console.log(newNumbers); // [1, 2, 3, 4, 5] ``` - The spread operator can also be used to **copy** the properties of an object into another object. ```jsx const person = { name: "John", age: 30 }; const newPerson = { ...person, }; console.log(newPerson); // { name: "John", age: 30 } ``` ### 1.5.7. Modules - **Modules** are reusable pieces of code that can be exported from one program and imported for use in another program. - Rely on the **_export_** and **_import_** statements. - Exporting a module: The **_export_** statement is used to export functions, objects, or primitive values from a module. - Named Exports: **_export_** keyword is used to export multiple named exports. ```jsx // Named Exports export const PI = 3.14; export function add(a, b) { return a + b; } ``` - Default Exports: **_export default_** keyword is used to export a single default export. (**Only one default export per module**) ```jsx // Default Export const PI = 3.14; export default PI; ``` - Import a module: The **_import_** statement is used to import functions, objects, or primitive values from a module. (**Named exports must be destructured using curly braces. Default exports are imported without curly braces.**) ```jsx // Named Exports import { PI, add } from "./math"; // Default Export import PI from "./math"; ``` ### 1.5.8. Ternary Operator - The **_ternary operator_** is the only JavaScript operator that takes **_three operands_**: a **_condition_** followed by a **_question mark_** (**_?_**), then an **_expression_** to execute if the condition is **_truthy_**, followed by a **_colon_** (**_:_)** and an **_expression_** to execute if the condition is **_falsy_**. ```jsx const age = 20; const message = age >= 18 ? "You are an adult" : "You are a minor"; console.log(message); // You are an adult ``` ## 1.6. React JSX You are not required to use JSX, but JSX makes it easier to write React applications. ```jsx // Example of JSX const element = <h1>Hello, world!</h1>; // Example of without JSX const element = React.createElement("h1", null, "Hello, world!"); ``` ### 1.6.1. JSX Expressions - JSX expressions are JavaScript expressions that can be used in JSX. ```jsx const name = "John"; const element = <h1>Hello, {name}</h1>; const myElement = <h1>React is {5 + 5} times better with JSX</h1>; ``` - JSX expressions can be used in attributes. ```jsx const url = "https://www.example.com"; const element = <a href={url}>Click here</a>; ``` - JSX expressions can be used in loops. ```jsx const numbers = [1, 2, 3, 4, 5]; const list = numbers.map((number) => <li>{number}</li>); const element = <ul>{list}</ul>; ``` ### 1.6.2. Insert large blocks of HTML - To insert large blocks of HTML, you can use **_parentheses_**. ```jsx const element = ( <div> <h1>Hello, world!</h1> <p>Welcome to React</p> </div> ); ``` ### 1.6.3. One top level element - In JSX, you must have only one top-level element. ```jsx // This will throw an error const element = <h1>Hello, world!</h1> <p>Welcome to React</p>; // This is correct const element = ( <div> <h1>Hello, world!</h1> <p>Welcome to React</p> </div> ); ``` - You can use **_React.Fragment_** to group multiple elements without adding an extra node to the DOM. ```jsx const element = ( <> <h1>Hello, world!</h1> <p>Welcome to React</p> </> ); ``` ### 1.6.4. Element must be closed - In JSX, you must close all elements. ```jsx // This will throw an error const element = <input type="text">; // This is correct const element = <input type="text" />; ``` ### 1.6.5. Attributes in JSX - In JSX, you can use **_attributes_** to add **_HTML attributes_** to elements. ```jsx const element = <img src="image.jpg" alt="My Image" />; ``` - **class** attribute is replaced with **_className_** in JSX. ```jsx const element = <div className="container">Hello, world!</div>; ``` ### 1.6.6. Style attribute in JSX - In JSX, you can use the **_style_** attribute to add **_inline styles_** to elements. ```jsx const myStyle = { color: "red", fontSize: "20px", }; const element = <h1 style={myStyle}>Hello, world!</h1>; ``` ## 1.7. React Components We have 2 types of components in React: - **Function Components**: A JavaScript function that accepts **_props_** and returns a **React element**. - **Class Components**: A JavaScript class that extends **_React.Component_** and has a **_render_** method that returns a **React element**. ### 1.7.1. Create first React component - **Function Component**: ```jsx function Welcome(props) { return <h1>Hello, world</h1>; } const element = <Welcome />; ``` - **Class Component**: ```jsx class Welcome extends React.Component { render() { return <h1>Hello, world</h1>; } } const element = <Welcome />; ``` ### 1.7.2. Rendering a Component - To render a React component into the DOM, you can use the **_ReactDOM.render()_** method. ```jsx const element = <Welcome />; ReactDOM.createRoot(document.getElementById("root")); root.render(element); // Or root.render(<Welcome />); ``` ### 1.7.3. Props - **Props** are used to pass data from a parent component to a child component. ```jsx // props in Function Component function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="John" />; // props in Class Component class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } const element = <Welcome name="John" />; ``` ### 1.7.4. Components in components - You can use components inside other components. ```jsx function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div> <Welcome name="John" /> <Welcome name="Sara" /> <Welcome name="Mike" /> </div> ); } const element = <App />; ``` ### 1.7.5. Component in a file - You can create a component in a separate file and import it into another file. ```jsx // Welcome.js function Welcome(props) { return <h1>Hello, {props.name}</h1>; } export default Welcome; ``` ```jsx // App.js import Welcome from "./Welcome"; function App() { return ( <div> <Welcome name="John" /> <Welcome name="Sara" /> <Welcome name="Mike" /> </div> ); } export default App; ``` ```jsx // index.js import App from "./App"; const element = <App />; ReactDOM.createRoot(document.getElementById("root")); root.render(element); ``` ### 1.7.6. React Class ##### Note: - Before React 16.8, class components were the only way to create stateful components in React. - With the introduction of **_Hooks_** in React 16.8, you can now use state and other React features in functional components. - The differences are so minor that you will probably never need to use a Class component in React. - Feel free to skip this section, and use Function Components instead. #### 1.7.6.1. Class Component - A class component is a JavaScript class that extends **_React.Component_**. The component's name must start with an upper case letter. ```jsx class Welcome extends React.Component { render() { return <h1>Hello, world</h1>; } } const element = <Welcome />; ``` #### 1.7.6.2. Constructor - The **_constructor_** method is a special method for creating and initializing an object created with a class. ```jsx class Welcome extends React.Component { constructor(props) { super(props); this.state = { name: "John" }; } render() { return <h1>Hello, {this.state.name}</h1>; } } const element = <Welcome />; ``` #### 1.7.6.3. Props - You can access **_props_** in a class component using **_this.props_**. ```jsx class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } const element = <Welcome name="John" />; ``` #### 1.7.6.4. State - **State** is an object that holds some information that may change over the lifetime of the component. ```jsx class Welcome extends React.Component { constructor(props) { super(props); this.state = { name: "John" }; } render() { return <h1>Hello, {this.state.name}</h1>; } } const element = <Welcome />; ``` ### 1.7.7. React Props - **Props** are used to pass data from a parent component to a child component. - React Props are read-only! You will get an error if you try to change their value. ```jsx // Function Component function Welcome(props) { return <h1>Hello, {props.name}</h1>; } const element = <Welcome name="John" />; // Class Component class Welcome extends React.Component { render() { return <h1>Hello, {this.props.name}</h1>; } } const element = <Welcome name="John" />; ``` - We can pass variables, functions, or objects as props. ```jsx // Passing variables const name = "John"; const element = <Welcome name={name} />; // Passing functions function handleClick() { alert("Button clicked"); } const element = <button onClick={handleClick}>Click me</button>; // Passing objects const person = { name: "John", age: 30 }; const element = <Welcome person={person} />; ``` ### 1.7.8. React Events - **Events** are actions that occur when a user interacts with a web page. ```jsx function handleClick() { alert("Button clicked"); } const element = <button onClick={handleClick}>Click me</button>; ``` - **Event handlers** are functions that are executed when an event occurs. ### 1.7.9. React Forms - **Forms** are used to collect user input in a web page. ```jsx function MyForm() { return ( <form> <label> Enter your name: <input type="text" /> </label> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` - Handling Forms: | HTML | React | |---|---| | Form data is usually handled by the DOM | - Form data is usually handled by the components<br>- The data is stored in the component state | - Control changes by adding event handlers in the onChange attribute. - Use the useState Hook to keep track of each inputs value and provide a "single source of truth" for the entire application. ```jsx function MyForm() { const [name, setName] = React.useState(""); const handleChange = (event) => { setName(event.target.value); }; return ( <form> <label> Enter your name: <input type="text" value={name} onChange={handleChange} /> </label> <p>Your name is: {name}</p> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` - Submitting Forms: - Use the onSubmit attribute to specify a function that will be called when the form is submitted. - Use the preventDefault() method to prevent the default action of the form. ```jsx function MyForm() { const [name, setName] = React.useState(""); const handleSubmit = (event) => { event.preventDefault(); alert("Form submitted"); }; const handleChange = (event) => { setName(event.target.value); }; return ( <form onSubmit={handleSubmit}> <label> Enter your name: <input type="text" value={name} onChange={handleChange} /> </label> <button type="submit">Submit</button> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` - Multiple input fields: - Use the **_name_** attribute to specify the name of the input field. - Use the **_value_** attribute to specify the value of the input field. - Use the **_onChange_** attribute to specify a function that will be called when the input field changes. ```jsx import { useState } from "react"; import ReactDOM from "react-dom/client"; function MyForm() { const [inputs, setInputs] = useState({}); const handleChange = (event) => { const name = event.target.name; const value = event.target.value; setInputs((values) => ({ ...values, [name]: value })); }; const handleSubmit = (event) => { event.preventDefault(); alert(inputs); }; return ( <form onSubmit={handleSubmit}> <label> Enter your name: <input type="text" name="username" value={inputs.username || ""} onChange={handleChange} /> </label> <label> Enter your age: <input type="number" name="age" value={inputs.age || ""} onChange={handleChange} /> </label> <input type="submit" /> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` - Textarea: - Use the **_textarea_** element to create a multi-line text input field. - Use the **_value_** attribute to specify the value of the textarea. - Use the **_onChange_** attribute to specify a function that will be called when the textarea changes. ```jsx function MyForm() { const [message, setMessage] = React.useState(""); const handleChange = (event) => { setMessage(event.target.value); }; return ( <form> <label> Enter your message: <textarea value={message} onChange={handleChange} /> </label> <p>Your message is: {message}</p> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` - Select: - Use the **_select_** element to create a drop-down list. - Use the **_value_** attribute to specify the value of the select element. - Use the **_onChange_** attribute to specify a function that will be called when the select element changes. ```jsx function MyForm() { const [fruit, setFruit] = React.useState("apple"); const handleChange = (event) => { setFruit(event.target.value); }; return ( <form> <label> Select your favorite fruit: <select value={fruit} onChange={handleChange}> <option value="apple">Apple</option> <option value="banana">Banana</option> <option value="orange">Orange</option> </select> </label> <p>Your favorite fruit is: {fruit}</p> </form> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<MyForm />); ``` ## 1.8. React Router - _Create React App doesn't include page routing._ - **React Router** is a collection of navigational components that compose declaratively with your application. ```bash npm i -D react-router-dom ``` ### 1.8.1. Folder Structure - **src**: Contains the source code of the application. - **src/components**: Contains the components of the application. - **src/pages**: Contains the pages of the application. - **src/App.js**: The main component of the application. `src\pages\:` - `Home.js`: The Home page of the application. - `Layout.js`: The layout component of the application. - `Blog.js`: The Blog page of the application. - `Contact.js`: The Contact page of the application. - `NoPage.js`: The 404 page of the application. #### 1.8.2. Basic Usage ```jsx // index.js import ReactDOM from "react-dom/client"; import { BrowserRouter, Routes, Route } from "react-router-dom"; import Layout from "./pages/Layout"; import Home from "./pages/Home"; import Blogs from "./pages/Blogs"; import Contact from "./pages/Contact"; import NoPage from "./pages/NoPage"; export default function App() { return ( <BrowserRouter> <Routes> <Route path="/" element={<Layout />}> <Route index element={<Home />} /> <Route path="blogs" element={<Blogs />} /> <Route path="contact" element={<Contact />} /> <Route path="*" element={<NoPage />} /> </Route> </Routes> </BrowserRouter> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); ``` Explain: - **BrowserRouter**: A router that uses the HTML5 history API to keep your UI in sync with the URL. - **Routes**: A collection of routes that render their children when their path matches the current URL. An application can have multiple `<Routes>`. - **Route**: A route that renders its children when its path matches the current URL. `<Route>s` can be nested. - The `index` attribute is used to specify the default route (`/`). - Setting path to `*` will match all paths that are not matched by other routes. #### 1.8.3 Pages / Components ```jsx // Layout.js import { Outlet, Link } from "react-router-dom"; const Layout = () => { return ( <> <nav> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/blogs">Blogs</Link> </li> <li> <Link to="/contact">Contact</Link> </li> </ul> </nav> <Outlet /> </> ); }; export default Layout; ``` ```jsx // Home.js const Home = () => { return <h1>Home Page</h1>; }; export default Home; ``` ```jsx // Blogs.js const Blogs = () => { return <h1>Blogs Page</h1>; }; export default Blogs; ``` ```jsx // Contact.js const Contact = () => { return <h1>Contact Page</h1>; }; export default Contact; ``` ```jsx // NoPage.js const NoPage = () => { return <h1>404 Page</h1>; }; export default NoPage; ``` Explain: - The Layout component has `<Outlet>` and `<Link>` elements. - The `<Outlet>` renders the current route selected. - `<Link>` is used to set the URL and keep track of browsing history. - Anytime we link to an internal path, we will use `<Link>` instead of `<a href="">`. - The "layout route" is a shared component that inserts common content on all pages, such as a navigation menu. ## 1.9. React Hooks - Allow function components to use state and other React features without writing a class. ### 1.9.1. What is a Hook? - **Hooks** are functions that let you use state and other React features in functional components. - **Hooks** are a new addition in React 16.8. - **Hooks** don't work inside classes. #### Hook rules - **Only call Hooks at the top level**: Don't call Hooks inside loops, conditions, or nested functions. - **Only call Hooks from React functions**: Call Hooks from React function components and not just any regular JavaScript function or class. - **Hooks cannot be conditional**: Don't call Hooks conditionally. ### 1.9.2. useState() To use state in a functional component, you can use the **_useState()_** Hook. ```jsx import { useState } from "react"; ``` - **useState()** is a Hook that allows you to add state to a functional component. ```jsx import { useState } from "react"; function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); } ``` #### Initializing State **useState()** accepts an argument that represents the initial state value. ```jsx import { useState } from "react"; function FavoriteColor() { const [color, setColor] = useState(""); } ``` #### Reading State ```jsx import { useState } from "react"; import ReactDOM from "react-dom/client"; function FavoriteColor() { const [color, setColor] = useState("red"); return <h1>My favorite color is {color}!</h1>; } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<FavoriteColor />); ``` #### Updating State To update our state, we use our state updater function. This function will update the state and re-render the component. **We should never directly update state. Ex: color = "red" is not allowed.** ```jsx import { useState } from "react"; import ReactDOM from "react-dom/client"; function FavoriteColor() { const [color, setColor] = useState("red"); return ( <> <h1>My favorite color is {color}!</h1> <button type="button" onClick={() => setColor("blue")}> Blue </button> </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<FavoriteColor />); ``` #### What Can State Hold **useState()** can hold any type of data, such as strings, numbers, arrays, and objects. ```jsx const [name, setName] = useState("John"); const [age, setAge] = useState(30); const [colors, setColors] = useState(["red", "green", "blue"]); const [person, setPerson] = useState({ name: "John", age: 30 }); ``` #### Updating State Based on Previous State When updating state based on the previous state, you can pass a function to **_setState()_**. ```jsx const [count, setCount] = useState(0); const increment = () => { setCount((prevCount) => prevCount + 1); }; ``` #### Updating State Based on Previous State (Object) When updating state based on the previous state (object), you can pass a function to **_setState()_**. ```jsx const [person, setPerson] = useState({ name: "John", age: 30 }); const updatePerson = () => { setPerson((prevPerson) => { return { ...prevPerson, age: prevPerson.age + 1 }; }); }; ``` ### 1.9.3. useEffect() - The **_useEffect()_** Hook is used to perform side effects in a functional component. - Some examples of side effects are: fetching data, directly updating the DOM, and timers. - `useEffect` accepts two arguments. The second argument is optional. ```jsx useEffect(() => { // Side effect }, [dependencies]); // Or useEffect(<function>, [dependencies]) ``` Example: ```jsx // Use setTimeout() to count 1 second after initial render: import { useState, useEffect } from "react"; import ReactDOM from "react-dom/client"; function Timer() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { setCount((count) => count + 1); }, 1000); }); return <h1>I've rendered {count} times!</h1>; } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<Timer />); ``` - useEffect runs on every render by default. - To run useEffect only once, pass an empty array as the second argument. ```jsx useEffect(() => { // Side effect }, []); ``` - To run useEffect only when a specific value changes, pass that value in the array. ```jsx import { useState, useEffect } from "react"; import ReactDOM from "react-dom/client"; function Counter() { const [count, setCount] = useState(0); const [calculation, setCalculation] = useState(0); useEffect(() => { setCalculation(() => count * 2); }, [count]); // <- add the count variable here and if the count variable updates, the effect will run again: return ( <> <p>Count: {count}</p> <button onClick={() => setCount((c) => c + 1)}>+</button> <p>Calculation: {calculation}</p> </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<Counter />); ``` #### Cleanup - **_useEffect()_** can return a function that will be called when the component is unmounted or before the effect runs again. ```jsx useEffect(() => { // Side effect return () => { // Cleanup }; }, []); ``` ```jsx useEffect(() => { // Note: To clear the timer, we had to name it. const interval = setInterval(() => { // Side effect }, 1000); return () => { clearInterval(interval); }; }, []); ``` ### 1.9.4. useContext() - The **_useContext()_** is a way to manage state globally. - The **_useContext()_** Hook is used to access the value of a context. #### Create a Context - Create a context using the **_createContext()_** function. ```jsx import { useState, createContext } from "react"; import ReactDOM from "react-dom/client"; const UserContext = createContext(); ``` #### Provide a Context - Use the **_Provider_** component to provide the context value to its children. ```jsx const App = () => { const [user, setUser] = useState("John"); return ( <UserContext.Provider value={user}> <h1>{`Hello ${user}!`}</h1> <Component2 user={user} /> </UserContext.Provider> ); }; ``` Now, all components in this tree will have access to the user Context. #### Use a Context - Use the **_useContext()_** Hook to access the value of a context. ```jsx import { useState, createContext, useContext } from "react"; const Component2 = () => { const user = useContext(UserContext); return <h2>{`Hello ${user}!`}</h2>; }; ``` #### Full Example ```jsx import { useState, createContext, useContext } from "react"; import ReactDOM from "react-dom/client"; const UserContext = createContext(); function Component1() { const [user, setUser] = useState("Jesse Hall"); return ( <UserContext.Provider value={user}> <h1>{`Hello ${user}!`}</h1> <Component2 /> </UserContext.Provider> ); } function Component2() { return ( <> <h1>Component 2</h1> <Component3 /> </> ); } function Component3() { return ( <> <h1>Component 3</h1> <Component4 /> </> ); } function Component4() { return ( <> <h1>Component 4</h1> <Component5 /> </> ); } function Component5() { const user = useContext(UserContext); return ( <> <h1>Component 5</h1> <h2>{`Hello ${user} again!`}</h2> </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<Component1 />); ``` ### 1.9.5. useRef() - The **_useRef()_** Hook is used to create a mutable reference that persists for the lifetime of the component. - It can be used to access a DOM element directly. #### Does Not Cause Re-renders - **_useRef()_** does not cause re-renders when the value changes. ```jsx // Use useRef to track application renders. import { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom/client"; function App() { const [inputValue, setInputValue] = useState(""); const count = useRef(0); useEffect(() => { count.current = count.current + 1; }); return ( <> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <h1>Render Count: {count.current}</h1> </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); ``` - `useRef()` only returns one item. It returns an Object called `current`. - It's like doing this: `const count = {current: 0}`. We can access the count by using `count.current`. #### Accessing DOM Elements - **_useRef()_** can be used to access DOM elements directly. ```jsx import { useRef } from "react"; function App() { const inputRef = useRef(); const handleClick = () => { inputRef.current.focus(); }; return ( <> <input type="text" ref={inputRef} /> <button onClick={handleClick}>Focus</button> </> ); } ``` #### Tracking state changes ```jsx // Use useRef to keep track of previous state values: import { useState, useEffect, useRef } from "react"; import ReactDOM from "react-dom/client"; function App() { const [inputValue, setInputValue] = useState(""); const previousInputValue = useRef(""); useEffect(() => { previousInputValue.current = inputValue; }, [inputValue]); return ( <> <input type="text" value={inputValue} onChange={(e) => setInputValue(e.target.value)} /> <h2>Current Value: {inputValue}</h2> <h2>Previous Value: {previousInputValue.current}</h2> </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<App />); ``` ### 1.9.6. useReducer() - The **_useReducer()_** Hook is used to manage complex state logic in a component. - It is similar to **_useState()_**, but it accepts a reducer function with the current state and an action. #### Syntax ```jsx // useReducer(<reducer>, <initialState>) const [state, dispatch] = useReducer(reducer, initialState); ``` - The reducer function contains your custom state logic and the initialState can be a simple value but generally will contain an object. - The useReducer Hook returns the current state and a dispatch method. #### Usage ```jsx import { useReducer } from "react"; import ReactDOM from "react-dom/client"; const initialTodos = [ { id: 1, title: "Todo 1", complete: false, }, { id: 2, title: "Todo 2", complete: false, }, ]; const reducer = (state, action) => { switch (action.type) { case "COMPLETE": return state.map((todo) => { if (todo.id === action.id) { return { ...todo, complete: !todo.complete }; } else { return todo; } }); default: return state; } }; function Todos() { const [todos, dispatch] = useReducer(reducer, initialTodos); const handleComplete = (todo) => { dispatch({ type: "COMPLETE", id: todo.id }); }; return ( <> {todos.map((todo) => ( <div key={todo.id}> <label> <input type="checkbox" checked={todo.complete} onChange={() => handleComplete(todo)} /> {todo.title} </label> </div> ))} </> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render(<Todos />); ``` - This is just the logic to keep track of the todo complete status. - All of the logic to add, delete, and complete a todo could be contained within a single useReducer Hook by adding more actions. ### 1.9.7. useCallback() - The **_useCallback()_** Hook is used to memoize functions. - It returns a memoized version of the callback function that only changes if one of the dependencies has changed. #### Note: Not done yet ### 1.9.8. useMemo() - The **_useMemo()_** Hook is used to memoize values. - It returns a memoized value that only changes when one of the dependencies has changed. - It is similar to **_useCallback()_**, but it is used for memoizing values instead of functions. #### Note: Not done yet