Published on

Getting Started with Hooks in React

1441 words8 min read
Authors
  • avatar
    Name
    Curtis Warcup
    Twitter

Hooks are a way to write reusable code, instead of more classic techniques like inheritance.

Hooks System

  • useState
    • function that lets you use state in a functional component.
  • useEffect
    • function that lets you use something like lifecycle methods in a functional component.
  • useRef
    • function that lets you create a 'ref' in a functional component.

Primitive Hooks

Are built-in react functions:

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRed
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

Custom Hook

May reuse a few primitive hooks from react. We can create our own and should be reusable.

useState

React docs:

Used to give us access to the state system within a functional component. Previously, this was not possible with functional components, only class based components.

Example with hooks in a functional component:

import React, { useState } from 'react'

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  )
}

Same example but using class components:

class Example extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 0,
    }
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click me</button>
      </div>
    )
  }
}

One last example of useState:

export default function App() {
  const [count, setCount] = useState(0) // initialize

  const onButtonClick = () => {
    // setter function
    setCount(count + 1)
  }

  return (
    <div>
      <button onClick={onButtonClick}>Click Me!</button> // invoking setter function
      <h1>Current Count: {count}</h1>
    </div>
  )
}

useState syntax

const [activeIndex, setActiveIndex] = useState(null);

This is known as array destructuring. Is the same idea as object destructuring. Basically a shortcut to get references to elements within an array.

Whenever we call useState() we get access to two elements inside it.

The first element in the array is something we want to keep track of, it will change over time. In our case, we are keeping track of the count. When you click the button, it increments the value.

The second element in the array, named as setFirstVariableName, is a function we call to update our piece of state. Anytime we call the setter function, it will cause our entire component to re-render.

The named of the first and second elements are NOT special. They can be anything we want.

Initialize, reference and updating hooks

Comparing class and function components:

Multiple State Variables

In functional components, we call useState multiple times.

const [activeIndex, setActiveIndex] = useState(0)
const [term, setTerm] = useState('')

Same goes for if we want to update those states, we need to call the setter for each state we are following.

setActiveIndex(10)
setTerm('Gilligan')

Back in class based components, we can initialize states very easily, like so: state = { activeIndex:0, term: '' }

Setter Function

Whenever you invoke the setter function (setSomething), it will change the value of the variable which is changing state. It will NOT go back to the default value.

Text Input with hooks

Here our state is update on every keystroke in the search bar:

import React, { useState } from 'react'

const Search = () => {
  const [term, setTerm] = useState('')

  return (
    <div className="ui form">
      <div className="field">
        <label>Enter Search Term</label>
        <input value={term} onChange={(e) => setTerm(e.target.value)} className="input"></input>
      </div>
    </div>
  )
}

export default Search

useEffect - how to detect that a state has changed

React Docs on useEffect:

  • Allows function components to use something like lifecycle methods.
  • We configure the hook to run some code automatically in one of three scenarios.
    1. when the component is rendered for the first time only.
    2. when the component is rendered for the first time and whenever it re-renders.
    3. when the component is rendered for the first time, whenever it re-renders, and some piece of data has changed.

We have to tell React when we want to use effect, i.e., one of the three scenarios above. We do this by providing a second argument.

const Search = () => {
  const [term, setTerm] = useState('');

  useEffect(() => {
    console.log('aasdf');
  }, [term]); // second term used to determine when to use effect

Async with useEffect

Making a request to an API while using the useEffect hook.

Option 1: Wrap the request in (), and then immediately call it.

useEffect(() => {
  ;(async () => {
    await axios.get('ddsfg')
  })()
}, [term])

Option 2: Use normal promises.

useEffect(() => {
  axios.get('asd').then((response) => {
    console.log(response.data)
  })
}, [term])

Option 3: Define a new function inside of useEffect, mark it as async, then call it manually.

const App = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    // define new function as async
      const getData = async () => {
          const { data } = await axios.get(URL); //add await to make it async
          setUsers(data)
      };

      // call async function manually
      getData();



  }, []);

dangerouslySetInnerHTML - XSS Attack

<span dangerouslySetInnerHTML={{ __html: result.snippet }}></span>

Take a string from a 3rd party (API in our case) and execute it as HTML. Can slo do