Skip to content

Instantly share code, notes, and snippets.

@SoftwareDevPro
Created February 12, 2021 23:56
Show Gist options
  • Save SoftwareDevPro/6df8a2524a2b458ce7e877a8fb89a33d to your computer and use it in GitHub Desktop.
Save SoftwareDevPro/6df8a2524a2b458ce7e877a8fb89a33d to your computer and use it in GitHub Desktop.
React Hooks Cheatsheet

React Hooks Cheatsheet

useState Hook

The useState hook allows us to create state variables in a React function component.

Create State Variables with useState

import { useState } from 'react';

export default function App() {
    const [ language ] = useState('Javascript')
    return <h1>I am learning {language}</h1>;
}

Update State Variables

import { useState } from 'react';

export default function App() {

    const [ language, setLanguage ] = useState('Javascript')

    function changeLanguage() {
        setLanguage('React Hooks')
    }

    return <h1 onClick={changeLanguage}>I am learning {language}</h1>;
}

Can Be Used Once Or Many Times

import { useState } from 'react';

export default function App() {

    const [language, setLanguage] = useState('Javascript')

    function changeLanguage() {
        setLanguage('React Hooks')
    }

    return <h1 onClick={changeLanguage}>I am learning {language}</h1>;
}

Update State based on Previous Value


import { useState } from "react";

export default function App() {

    const [ language, setLanguage ] = useState("Javascript");
    const [ years, setYears ] = useState(0);

    function changeLanguage() {
        setLanguage("React Hooks");
    }
    function addYear() {
        setYears(prev => prev + 1)
    }

    return (
        <div>
            <h1 onClick={changeLanguage}>
                I've learned {language} for {years} years
            </h1>
            <button onClick={addYear}>Add Year</button>
        </div>
    );
}

Manage State with an Object

import { useState } from "react";

export default function App() {

    const [ state, setState ] = useState({
        language: "Javascript",
        years: 0
    })

    function changeLanguage() {
        setState({...state, language: "React Hooks"});
    }

    function addYear() {
        setState(prev => {
            return {
                ...prev,
                years: prev.years + 1
            }
        })
    }

    return (
        <div>
            <h1 onClick={changeLanguage}>
                I've learned {state.language} for {state.years} years
            </h1>
            <button onClick={addYear}>Add Year</button>
        </div>
    );
}

useEffect Hook

The useEffect hook lets us perform side effects in function components. Side effects are when we need to reach into the outside world. Such as fetching data from an API or working with the DOM. Side effects are actions that can change our component state in an unpredictable fashion (that have cause 'side effects'). The useEffect hook accepts a callback function (called the 'effect' function), which will by default run every time the component re-renders.

Perform Side Effects with useEffect

import { useEffect } from "react";

export default function App() {

    useEffect(() => {
        document.body.style.background = 'blue';
        document.body.style.color = 'orange';
    })

    return (
        <div>
            <h1>React App</h1>
        </div>
    );
}

Run Again when a Value Changes

import { useEffect, useState } from "react";

export default function App() {
    
    const [ color, setColor ] = useState('blue')

    useEffect(() => {
        document.body.style.background = color;
        document.body.style.color = 'grey';
    }, [color]);

    function changeColor() {
        setColor('gold')
    }

    return (
        <div>
            <h1>React App</h1>
            <button onClick={changeColor}>Change color</button>
        </div>
    );
}

Unsubscribe by Returning a Function

import { useState, useEffect } from "react";

export default function App() {

    const [ color, setColor ] = useState('blue');

    useEffect(() => {
        document.body.style.background = color;
        document.body.style.color = 'orange';
        window.addEventListener('keydown', handleEnterButton)

        return () => {
            window.removeEventListener('keydown', handleEnterButton)
        }

    }, [color]);

    function changeColor() {
        setColor('gold')
    }

    function handleEnterButton(event) {
        if (event.keyCode === 13) {
            setColor('red')
        }
    }

    return (
        <div>
            <h1>React App</h1>
            <button onClick={changeColor}>Get color</button>
        </div>
    );
}

Fetch Data from an API

import { useState, useEffect } from "react";

export default function App() {
    
    const [ color, setColor ] = useState('blue');
    const [ user, setUser ] = useState(null);

    useEffect(() => {
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(res => res.json())
            .then(data => setUser(data[0]))
    }, [])

    useEffect(() => {
        document.body.style.background = color;
        document.body.style.color = 'white';
        window.addEventListener('keydown', handleEnterButton);

        return () => {
            window.removeEventListener('keydown', handleEnterButton)
        }
    }, [color]);

    function changeColor() {
        setColor('gold')
    }

    function handleEnterButton(event) {
        if (event.keyCode === 13) {
            setColor('red')
        }
    }

    return (
        <div>
            <h1>React App</h1>
            <button onClick={changeColor}>Get color</button>
            <br />
            <br />
            Current user: <pre>{JSON.stringify(user, null, 2)}</pre>
        </div>
    );
}

useRef Hook

Refs are a special attribute that are available on all React components. They allow us to create a reference to a given element / component when the component mounts. The useRef hook allows us to easily use React refs. They are helpful (as in the example below) when we want to directly interact with an element, such as to clear its value or focus it, as with an input.

Reference React Elements with useRef

import { useRef } from 'react';

export default function App() {
    
    const inputRef = useRef(null);

    function handleClearInput() {
        inputRef.current.value = "";
        inputRef.current.focus();
    }

    return (
        <form>
            <input type="text" ref={inputRef} />
            <button type="button" onClick={handleClearInput}>
                Clear Input
            </button>
        </form>
    );
}

useCallback Hook

The useCallback hook is used for improving our component performance. Callback functions are the name of functions that are "called back" within a parent component. The most common usage is to have a parent component with a state variable, but you want to update that state from a child component. useCallback memoizes our callback functions, so they not recreated on every re-render. Using useCallback correctly can improve the performance of our app.

useCallback Prevents Callbacks from Being Recreated

import { useState, useCallback, memo } from 'react';

export default function App() {

    const [ skill, setSkill ] = useState("");
    const [ skills, setSkills ] = useState(["HTML", "CSS", "JavaScript"]);

    function handleChangeInput(event) {
        setSkill(event.target.value);
    }

    function handleAddSkill() {
        setSkills(skills.concat(skill));
    }

    const handleRemoveSkill = useCallback((skill) => {
        setSkills(skills.filter((s) => s !== skill));
    }, [skills])

    return (
        <>
            <input onChange={handleChangeInput} />
            <button onClick={handleAddSkill}>Add Skill</button>
            <SkillList skills={skills} handleRemoveSkill={handleRemoveSkill} />
        </>
    );
}

const SkillList = memo(({ skills, handleRemoveSkill }) => {
    
    console.log('re-rendered whenever parent state is updated!')

    return (
        <ul>
            {skills.map((skill) => (
                <li key={skill} onClick={() => handleRemoveSkill(skill)}>
                    {skill}
                </li>
            ))}
        </ul>
    );
});

useMemo Hook

The useMemo hook is very similar to useCallback and is for improving performance, but instead of being for callbacks, it is for storing the results of expensive operations. useMemo allows us to memoize, or remember the result of expensive operations when they have already been made for certain inputs. Memoization means that if a calculation has been done before with a given input, there's no need to do it again, because we already have the stored result of that operation.

useMemo Can Improve Expensive Operations

import { useState, useMemo } from 'react';

const skills = [ "HTML", "CSS", "JavaScript", 'C++', 'Elm' ];

export default function App() {

    const [searchTerm, setSearchTerm] = useState("");
    
    const searchResults = useMemo(() => {
        return skills.filter(s => s.includes(searchTerm));
    }, [searchTerm])

    function handleSearchInput(event) {
        setSearchTerm(event.target.value);
    }
    
    return (
        <>
            <h3>Search Results</h3>
            <input onChange={handleSearchInput} />
            <ul>
                {searchResults.map((result, i) => (
                    <li key={i}>{result}</li>
                ))}
            </ul>
        </>
    );
}

useContext Hook

In React, we want to avoid the following problem of creating multiple props to pass data down two or more levels from a parent component. It is fine to pass props through multiple components, but it is redundant to pass props through components which do not need it. Context is helpful for passing props down multiple levels of child components from a parent component and sharing state across our app component tree. The useContext hook removes the unusual-looking render props pattern that was required in consuming React Context before.

useContext Helps Us Avoid Prop Drilling

import { createContext, useState, useContext} from 'react';

const UserContext = createContext()

export default function App() {

    const [user] = useState({ name: "Joe Smith" });

    return (
        <UserContext.Provider value={user}>
            <Main />
        </UserContext.Provider>
    );
}

const Main = () => (
    <>
        <Header />
        <br />
        <div>Main app content</div>
    </>
);

const Header = () => {
    const user = useContext(UserContext)
    return <h1>Welcome, {user.name}!</h1>;
}

useReducer Hook

The useReducer hook is for state management, much like useState and relies upon a kind of function called a reducer. Reducers are simple, predictable (pure) functions that take a previous state object and an action object and return a new state object. useReducer can be used in many of the same ways that useState can, but is more helpful for managing state across multiple components that may involve different operations or "actions".

useReducer may be used as an alternative to useState.

import { useReducer } from "react";

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'decrement'}) }>-</button>
      <button onClick={() => dispatch({ type: 'increment'}) }>+</button>
    </>
  );
}

export default function App() {
  return (
      <>
        <Counter />
      </>
  );
}

useLayoutEffect hook

To prevent the user from seeing flickers of changes, you may use useLayoutEffect.


import { useState, useLayoutEffect } from "react";

export default function App() {
  const [randomNumber, setRandomNumber] = useState(0)
  const [effectLogs, setEffectLogs] = useState([])

  useLayoutEffect(
    () => {
      setEffectLogs(prevEffectLogs => [...prevEffectLogs, 'effect function has been invoked'])
    },
    [randomNumber]
  )

  return (
    <div>
      <h1>{randomNumber}</h1>
      <button
        onClick={() => {
          setRandomNumber(Math.random())
        }}
      >
        Generate random number!
      </button>
      <div>
        {effectLogs.map((effect, index) => (
          <div key={index}>{'🍔'.repeat(index) + effect}</div>
        ))}
      </div>
    </div>
  )
} 

Custom Hooks

A custom React hook is a function that runs inside of a component. It can run other hooks or other functions inside it. These functions/hooks can be recursive too. It makes patterns like render props and higher-order components unnecessary.

Example Custom Simple Counter Hook

// counter-hook.js
import { useState } from "react";
function useCounter(val, step) {
  const [count, setCount] = useState(val);
  function Increment() {
    setCount(count + step);  }

  function Decrement() {
    setCount(count - step);  }

  return [count, Increment, Decrement];}

export default useCounter;

// App.js
import React from "react";
import useCounter from "./counter-hook";
function App() {
  const [count, Increment, Decrement] = useCounter(0, 1);
  return (
    <div className="App">
        <h1>{count}</h1>
        <button onClick={Increment}>Increment</button>
        <button onClick={Decrement}>Decrement</button>
    </div>
  );
}

export default App;

Example Custom Hook for Using Local Storage

import { useState, useEffect } from 'react';

export const useLocalStorage = (key, defaultValue) => {
   const storedValue = JSON.parse(localStorage.getItem(key));
   const [value, setValue] = useState(storedValue || defaultValue);

   useEffect(() => {
      localStorage.setItem(key, JSON.stringify(value));
   }, [value, key]);

   return [value, setValue];
}

function App() {
  const [items, setItems] = useLocalStorage('items', []);
  const removeItem = (itemToBeDeleted) => {
    setItems(items.filter((item) => itemToBeDeleted !== item));
  };

  return (
    <div className="App">
      <header className="App-header">
        To Do items
        <ItemList items={items} removeItem={removeItem} />
        <AddItemForm addItem={addItem} />
      </header>
    </div>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment