Intro to React Hooks

JavaScriptLA

Presented by Vijay Menon, Organizer

Visit: https://javascriptla.net to be on our mailing list for meetups and tutorials.

What's A Hook?

A hook is a term used quite often to indicate an "entrypoint" or a way into a "program" or piece of code, such as when code starts up, finishes, fires an event, and so on (sometimes called lifecycle methods).

For example: 

Webhooks are used to run code from a server when a server-side condition has been met, e.g. a new customer signs up for your service, and a webhook emails the customer thank you.

React Lifecycle Methods are used to hook into React by class components at different points in the React startup and re-render phase.   (E.g. componentDidMount, etc).

What Are React Hooks?

  • State Hooks:  Allows functional components to be able to use and set state.
  • Effect Hooks:  Used to run custom scripts after certain events have finished in React, such as when a component mounts or unmounts. 
  • Even more hooks, but for simplicity, we'll talk about those in a different lecture.

A new way to "hook" into features from React, starting in React 16.8

Why React Hooks?

Using classes to create components often traps code we might want to re-use for other components, mainly the lifecycle methods (e.g. componentDidMount, componentDidUpdate, componentWillUpdate, etc). 

 

Code written in these methods typically can't be shared with other components across our app without doing more complicated work (such as augmenting classes aka higher order components).

 

Rather than augment classes, or writing more classes in general, React Hooks is a central API that we can just use functions with, is easy to work with and gives non-class components a way to work with state and lifecycle methods.   This saves us on overhead!

useState

useState gives us a fast way to create state variables that our function components can consume.

Simply import it from React like so:

 

Then in your function, declare a variable to have state, as well as a variable to update the state (think getter & setter).   Using new ES6 Syntax, you can do both of these in one line with destructuring (need help with ES6?)


Here we are declaring a variable called counter, and a setCounter function that will be created with a state of 0 from useState.  You can name variables whatever you want, but it's a good practice to have the setter function start with "set" as its prefix, so it's easy to tell what it will do to the variable (e.g. if toggle, use toggleState).

 

 

Think of useState as similar to this.setState() from a class component, however we don't need to worry about merging old states with new states, nor work with just objects (values can be any type now)

import React, { useState } from "react"
let [ counter, setCounter ] = useState(0)
counter = 0
setCounter(counter + 1)

useState Example

useEffect

useEffect is similar to componentDidMount or componentDidUpdate, so if you want to run scripts after the app has rendered, or even re-rendered, use this function. However, be careful with this function!  We'll see why shortly.

To use useEffect, you must import it from React like so.

import React, { useState, useEffect } from 'react'
function App() {
  let [count, setCount] = useState(0)
  useEffect(()=>{
    if(count>0){
      $("#log").append("<p>User clicked the button</p>")
    }
  })

  return (
    <div className="text-center">
      <h1>React Hook Examples</h1>
      <p>The count is {count}</p>
      <button onClick={()=>setCount(count + 1)}>Increment Count</button>
      <div id="log"></div>
    </div>
  );
}

Anytime our counter increments, we want to log somewhere that action.  (Here I'm using jQuery as an example).  useEffect runs when the app loads and on every re-render, so I added an if statement to not log 0 if the app starts.

useEffect Example

Controlling useEffect

You may not want to re-render each time especially if state wasn't changed.  To do so, add an array with your state as a second argument to skip the useEffect function.

let [map, setMap] = useState(true);

useEffect(() => {
   let map = document.getElementById('map');
   someMapAPI.init(map); /* load map only once */
}, [map])

Here the map variable in [map] (second argument of useEffect) is compared to the initial state for map we set to be true, which if true again (true === true) prevents the useEffect function from firing off again.  We don't want two maps!

Cleaning Up useEffect

You might be wondering how to unmount custom code.  useEffect returns a function which serves as unmount code.

function App() {
  useEffect(()=>{
    function myHandler(event){
      alert('You clicked me, how dare you?')
    }
    document.addEventListener('click', myHandler)
    return function removeMyHandler(){
      document.removeEventListener(myHandler);
    }
  })

  return (    
    <div>
      <p>This is my body</p>
    </div>
  )
}

The useEffect function's return is used to return a function that serves as "cleanup" code, e.g. to remove any third party or direct DOM manipulation code (since they aren't managed by React and could cause memory leaks).  Again naming is up to you, but to clean up you need to return a function that removes any modifications you made to DOM.

Even More Hooks

Thank you!

Be sure to visit our website at: https://javascriptla.net.

 

Every month we have new meetups ONLINE, (you don't need to live in LA to attend) on topics like React, Angular, Node.js and more!

 

So be sure to get on our mailing list!  See you at the next meetup!

Made with Slides.com