Skip to content

Instantly share code, notes, and snippets.

@ross-u
Forked from diurivj/ad.md
Created October 8, 2019 15:27
Show Gist options
  • Save ross-u/364410075d94e9730ac4c9ddc2f02a66 to your computer and use it in GitHub Desktop.
Save ross-u/364410075d94e9730ac4c9ddc2f02a66 to your computer and use it in GitHub Desktop.

React | Hooks

Learning Goals

After this lesson you will be able to:

  • Understand what are React Hooks and why are so hot 🔥
  • Understand how to use useState()
  • Understand how to use useEffect()
  • Understand how to use useContext()
  • Learn how to create your own custom hook

Introduction

We've learned how to write React in a 2018 way, so now we'll learn how to write code as a 2019 hipster react developer do :neckbeard:

Introducing Hooks

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

Hooks are the way to access to the features of a class component without writing one. Amazing, right?

Hooks are functions that let you hook into React state and lifecycle features from function components. Hooks don’t work inside classes — they let you use React without classes. (We don’t recommend rewriting your existing components overnight but you can start using Hooks in the new ones if you’d like.)

React provides a few built-in Hooks like useState(). You can also create your own Hooks to reuse stateful behavior between different components. We’ll look at the built-in Hooks first.

useState()

Returns a stateful value, and a function to update it.

During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).

The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.

const [state, setState] = useState(initialValue)

Class Component vs Function Component

Class Component

import React, { Component } from 'react'

class App extends Component {
  state = {
    counter: 0
  }

  increment = () => {
    this.setState(prevState => {
      return prevState.counter++
    })
  }

  decrement = () => {
    this.setState(prevState => {
      prevState.counter--
    })
  }

  render() {
    const { counter } = this.state
    return (
      <>
        <h1>Counter: {counter}</h1>
        <button onClick={this.increment}>+</button>
        <button onClick={this.decrement}>-</button>
      </>
    )
  }
}

Edit class component counter

Function Component (with Hoooks)

import React, { useState } from 'react'

function App() {
  const [counter, setCount] = useState(0)

  const increment = () => {
    setCount(prevState => prevState + 1)
  }

  const decrement = () => {
    setCount(prevState => prevState - 1)
  }

  return (
    <>
      <h1>Counter: {counter}</h1>
      <button onClick={increment}>+</button>
      <button onClick={decrement}>-</button>
    </>
  )
}

Edit hungry-hopper-15my7

useEffect()

Accepts a function that contains imperative, possibly effectful code.

useEffect(didUpdate)

Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase). Doing so will lead to confusing bugs and inconsistencies in the UI.

Instead, use useEffect. The function passed to useEffect will run after the render is committed to the screen. Think of effects as an escape hatch from React’s purely functional world into the imperative world.

By default, effects run after every completed render, but you can choose to fire it only when certain values have changed.

import React, { useEffect } from 'react'

function App() {
  useEffect(() => {
    // This changes the title of the document after the completed render
    document.title = "Hello Ironhacker";
  }, []);

  return (
    <>
      <h1>Hello Ironhackers</h1>
    </>
  );
}

Edit cranky-gould-8ewtc

useContext()

Accepts a context object (the value returned from React.createContext) and returns the current context value for that context. The current context value is determined by the value prop of the nearest <MyContext.Provider> above the calling component in the tree.

const value = useContext(MyContext);

When the nearest <MyContext.Provider> above the component updates, this Hook will trigger a rerender with the latest context value passed to that MyContext provider.

Don’t forget that the argument to useContext must be the context object itself:

  • Correct: useContext(MyContext)
  • Incorrect: useContext(MyContext.Consumer)
  • Incorrect: useContext(MyContext.Provider)

A component calling useContext will always re-render when the context value changes. If re-rendering the component is expensive, you can optimize it by using memoization.

Custom Hooks

Building your own Hooks lets you extract component logic into reusable functions.

Traditionally in React, we’ve had two popular ways to share stateful logic between components: render props and higher-order components. We will now look at how Hooks solve many of the same problems without forcing you to add more components to the tree.

When we want to share logic between two JavaScript functions, we extract it to a third function. Both components and Hooks are functions, so this works for them too!

A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.

Unlike a React component, a custom Hook doesn’t need to have a specific signature. We can decide what it takes as arguments, and what, if anything, it should return. In other words, it’s just like a normal function. Its name should always start with use so that you can tell at a glance that the rules of Hooks apply to it.

function useForm() {
  const [form, setForm] = useState({
    name: "",
    email: "",
    password: ""
  })

  const onChange = e => {
    e.persist()
    setForm(prevState => ({
      ...prevState,
      [e.target.name]: e.target.value
    }))
  };

  const { name, email, password } = form;
  return {
    form,
    onChange,
    name,
    email,
    password
  }
}

function App() {
  const {name, email, password, onChange} = useForm()

  return (
    <>
      <input type="text" placeholder="Name" name="name" onChange={onChange}/>
      <br />
      <input type="email" placeholder="Email" name="email" onChange={onChange}/>
      <br />
      <input type="password" placeholder="Password" name="password" onChange={onChange} />
      <br />
      <br />
      <p>Name: {name}</p>
      <p>Email: {email}</p>
      <p>Password: {password}</p>
    </>
  )
}

Edit magical-bird-8u8t6

Extra Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment