--- title: React Essentials author: Garen Ikezian --- # What is a Component? Components in React is a JavaScript function that returns an HTML markup thereby allowing you to create reusable web templates/code. It is one of the key foundations in React and they always start with an uppercase letter to distinguish from vanilla HTML tags. ```js function SomeComponent(){ return (

This is a header

) } export default function Main(){ return( ) } ``` Important stuff to know in React: - **JSX**: It is an extension of HTML for Javascript. It is a convenient tool to have HTML tags inside a JavaScript file. - **Babel**: A transcompiler to make the new stuff in ECMAScript 2015+ or ES6 (some JavaScript version) to be backwards compatible to ES5. Since Babel can also understand JSX, it is used by React to transcompile its components. Ex: ```js // Babel Input: ES2015 arrow function [1, 2, 3].map(n => n + 1); // Babel Output: ES5 equivalent [1, 2, 3].map(function(n) { return n + 1; }); ``` - **Props**: It is short for "properties". They are static parameters of componenets (they are seen attributes in HTML tags). They are usually made for rendering purposes. Ex: ```js export default function Main(props) { return (

We serve the most {props.adjective}{" "} food around.

); } function App() { return (
); } ``` - **State**: It is a dynamic property (unlike regular static properties). It helps a component "remember" information and are used to keep track of something. States are not functions, they are just snapshots of data that changes with every render. # What is a Hook? Hooks in React are a function and are used to handle states for components. It is a convention for hooks to start with the word "use". There are different types of hooks. Some are built-in and some are custom made. # Understanding useState(), useEffect(), useReducer(), and useRef() Hooks ## [useState()](https://react.dev/reference/react/useState) `useState` is a hook that adds a state to a component. Syntax: ```js const [state, setState] = useState("state value"); ``` `useState` returns an array of two values. 1. The value of the state. 2. The `set` function that lets you change the value of that state. It's like a compact getter and setter method in Java or C#. ### Usage: `useState()` is best suited with user events handler like `onClick`, `onChange`, `onSelect` or any other HTML DOM events. ```js import {useState} from "react"; function App(){ const [name, setName] = useState("John"); return(

Hi! my name is {name}.

); } ``` Note however that the following is the **WRONG** way of using `useState()`. `setEmotion()` will change the value only *after* the rendering is done (or after the return statement): ```js import { useState } from "react"; function App(){ //We create a state like so const [emotion, setEmotion] = useState("Sad"); console.log(emotion.value); //emotion is "sad" setEmotion("Happy"); //Sad does not become "Happy". But this is the wrong way of using setEmotion(). console.log(emotion.value); //Still "Sad" return ( //It will not print anything. The console will show up with errors.

I am {emotion}

); } ``` Will lead to: ``` Too many re-renders. React limits the number of renders to prevent an infinite loop. ``` Since `setEmotion()` is called for every rendering on loop, the browser will then complain that it is "re-rendering" too much. From the browser's point of view, this is what it looks like: ```js function render(){ render(); } render(); ``` Because of this, we need a user event handler to prevent an infinite recursion. `setEmotion()` is supposed to be called only once every time the button is clicked. ## [useReducer()](https://react.dev/reference/react/useReducer) `useReducer()` is like `useState()`. But unlike `useState()`, `useReducer()` accepts static logic (represented as a function) as its parameter. ``` const [state, function] = useReducer(reducer, initialState) ``` Unlike having state logics being spread out throughout the code with `useState()`, `useReducer()` helps organize different state logic into its respective methods. ### Usage: ```js function reducer(state, action) { return { condition: !state.condition}; } function App(){ const [checked, toggleChecked] = useReducer(reducer, { condition: false }); return (
); } ``` Or you can use an arrow function to make the code A LOT more legible. ```js function App(){ const [checked, toggleChecked] = useReducer((checked) => !checked, false ); return (
); } ``` ## [useEffect()](https://react.dev/reference/react/useEffect) `useEffect()` is a hook that accepts a function and an optional list. With `useState()`, you (re-)initialize a component with a state. With `useEffect()`, you can perform side effects like directly fetching or updating the state of a component. It is made to output unpredictable results for the user. `useEffect()` is made to address the common misuse of `useState()`. However, its intended use is mainly for dealing data with third-party tools like backend servers, browser APIs, and timing functions like `setTimeout()` and `setInterval()`. In short, if you want an expected outcome, use `useState()`. If you want the webpage to interact with the outside world or expect unexpected results, use `useEffect()`. If your code does not involve (a)synchronization, you do not need `useEffect()`. More [here](https://react.dev/learn/you-might-not-need-an-effect). There are three possible usage scenarios: 1. Without a dependency (2nd param). **BAD USAGE** ```js setEffect( () => { //1st param: code that runs after *every* render }); ``` 2. With an empty list ```js setEffect( () => { //1st param: code that runs only on the first render }, []); ``` 3. With a list ```js setEffect( () => { //1st param: code that runs on the first render then after any dependency value change }, //2nd param: A dependency array of states specified. If its values change, the code in the 1st param above will run again. [...,...,...]); ``` ### Usage: To demonstrate how `useEffect()` looks like without a dependency, We use a `setTimeout()` method: ```js useEffect(() => { setTimeout(() => { setCount((count) => count + 1); }, 1000); }); return

I've rendered {count} times!

; ``` The rendering does not stop as the dependency does not exist. So we have to add an empty array as our second parameter. ```js useEffect(() => { setTimeout(() => { setCount((count) => count + 1); }, 1000); }, []); return

I've rendered {count} times!

; ``` Now it only renders once. ## [useRef()](https://react.dev/reference/react/useRef) All of the hooks mentioned above will require re-rendering when then their values are changed. `useRef()` however, is the exception. "ref" is short for reference. It lets you "reference"/remember a value without the need of re-rendering. ```js const ref = useRef(initialValue) ``` Note however that states and refs are two different things. `useRef()` does not rely on states as states trigger re-rendering when they are changed. A ref is just a plain JavaScript that can store a value that is used for later use. If we pass 0 to `useRef()`, ```js const ref = useRef(0); ``` `useRef()` returns an object like so (the browser will "see" this): ```js { current: 0 //the value passed to useRef } ``` "curent" is just an attribute of ref (`ref.current`). ### Usage Here, we hold the number of times the user clicked on a button. Unlike `useState()`, it does not trigger a re-render when the value is changed. ```js import { useRef } from 'react'; export default function Counter() { let ref = useRef(0); function handleClick() { ref.current = ref.current + 1; alert('You clicked '+ref.current+' times!'); } return (

You clicked me {ref.current} time(s)!

); } ``` Notice how the value of `ref.current` in the return statement is not updated. Refs do not re-render its components when they are re-rendered. They only serve as a storage space for later use. This [**table**](https://react.dev/learn/referencing-values-with-refs#differences-between-refs-and-state) from the manual is excellent to distinguish between refs and states apart. # Fetching Data with Hooks There is a link to output a user's data on Github. Let's the take the following example: ``` https://api.github.com/users/Garenium ``` This shows a user's Github data respresented as a JSON object. In order to fetch this with React, we use `useEffect()` like so: ```js import "./App.css"; import { useState, useEffect } from "react"; import { useReducer } from "react"; function App() { const [data,setData] = useState(null); useEffect(() => { fetch( `https://api.github.com/users/Garenium` ).then((response) => response.json()) .then(setData); }, []); if(data) return
{JSON.stringify(data,null,2)}
return (

Data

); } export default App; ``` The problem with this code is that it cannot handle three different states: - When the page is loading - When the page is finished loading - When there is a fetch problem Notice that when the webpage was loading, it was showing "Data" in a blink of an eye instead of the actual JSON object. This is because it is the asynchronous nature of the `useffect` hook. If we were to encounter a Github username that didn't exist, we would see this: ![Output when a Github user doesn't exist](image.png) It is recommended to create three different states like so: ```js import "./App.css"; import { useState, useEffect } from "react"; //Create a separate component for extract Github user data after useEffect is //done function GithubUser({ name, location, avatar }) { return (

{name}

{location}

{name}
); } function App() { //The three states: const [data, setData] = useState(null); //Data to load fetch const [error, setError] = useState(null); //setError when fetching fails const [loading, setLoading] = useState(false); //setLoading before data is set useEffect(() => { setLoading(true); fetch( `https://api.github.com/users/moonhighway` ) .then((response) => response.json()) .then(setData) .then(() => setLoad(false)) .catch(setError); }, []); if(loading) return

Loading...

//Show this when the state is loading if(error) return
{JSON.stringify(error)}
//When fetching fails. stringify error if(!data) return null; //return null when there's no data return ( ); } export default App; ```