Hooks

There are two types of components in React.

  1. Class Component – This is the method of creating a component using a class. It is the default way of building components in React. The reason why Class Components are commonly used is because they allow access to state and lifecycle methods, which is a significant advantage.

  2. Function Component – The Function Component has the drawback of not being able to directly use state and lifecycle methods. It is primarily used to simply return JSX.


React Class Components are widely used, but they have several issues:

  1. It is difficult to reuse logic with state across different components.
  2. Complex components are hard to understand.
  3. Classes are a confusing concept for both people and machines. To solve these problems, Hooks were developed.

By using Hooks, even function components can define state and lifecycle methods. However, the way state is defined using Hooks is different from the traditional class-based state. Additionally, Hooks can only be used in function components. If you try to define and use Hooks in a Class Component, an error like the one below will appear in the console.

To use Hooks, you need to have React version 16.8 or later installed. The first step in using Hooks is to import useState and useEffect from the React library for basic setup.

import React, { useState, useEffect } from 'react';

function App() {
  .... 
}

useState is set up so that state used in class components can now be used in function components. While the method of defining state is slightly different, if you're familiar with state, you can use it easily. To help understand, I'll show an example using a button click event.

  1. useState is created using an array. When defining a single state, you set it as [stateName, setStateName] and input the initial value inside the parentheses next to useState. One difference with Hooks is that it does not merge the previous and new state. The following example sets up a Boolean state to check whether the button has been clicked or not.

    ...
    function App() {
      const [buttonClicked, setButtonClicked] = useState(false);
    }
    
  2. When defining multiple states, you can first define one state, then input multiple initial state values inside useState to handle them all at once.

    ...
    function App() {
      const [state, setState] = useState({
        buttonClicked: false,
        name: ''
      })
    }
    

In this way, you can declare state and setState in the same manner as in class components. In Hooks, you can also declare props inside the render function just like you do with state.

...
function App(props) {
   const [buttonClicked, setButtonClicked] = useState(props.buttonClicked);
}

Now, I'll explain two ways to use setState.

  1. Declare it where the event happens.
function App() {
  const [buttonClicked, setButtonClicked] = useState(false);

  return(
    <div className="App">
      <p> button clicked: {buttonClicked}</p>
      <button onClick={() => setButtonClicked(true)}> True Click! </button>
      <button onClick={() => setButtonClicked(false)}> False Click! </button>
    </div>
  )
}
export default App;
  1. Declare it as a function, and then call it in the return part to use it.
...
function App() {
  const [buttonClicked, setButtonClicked] = useState(false);

  function setTrue() {
    setButtonClicked(true)
  }

  function setFalse() {
    setButtonClicked(false)
  }

  return (
    <div className="App">
      <p> button clicked: {buttonClicked} </p>
      <button onClick={setTrue}> True Click! </button>
      <button onClick={setFalse}> False Click! </button>
    </div>
  )
}
export default App;

In this way, you can easily declare state and setState, and use useState in Hooks to manage state changes. Next, let's learn how to apply lifecycle methods using useEffect in Hooks.

In Class Components, lifecycle methods were applied by using various functions such as componentDidMount, componentDidUpdate, etc. However, in Hooks, all lifecycle changes can be applied with just useEffect.

Let me show you how to use useEffect with an example.

...
function App() {
  useEffect(() => {
    doingSomething()
  }, [])
}
...

As shown in the example above, using useEffect is equivalent to componentDidMount in Class Components, where you can perform initial setup. The [] part means it will run only once after the first render and will not run again, similar to how componentDidMount works. Now, let me show you how to detect state or prop changes and apply a componentDidUpdate-like setup.

...
function App() {
  useEffect(() => {
    doingSomethingWhenButtonClickedChange()
  }, [buttonClicked])
}
...

As shown in the example above, you can input the value you want to detect changes for inside the []. The component will update every time that value changes. This way, useEffect can directly detect lifecycle changes and handle them. It may seem confusing at first, but once you get used to it, useEffect is simpler and more versatile than lifecycle methods.

When using useEffect, always set [] to avoid an infinite loop and ensure proper function. To handle lifecycle changes (other than initialization), you must declare which value will trigger the lifecycle update.


Here are some important points to note when using Hooks:

  1. Hooks should only be used in function components.
  2. Hooks should be called at the top level only. They should not be called inside conditionals, loops, or nested functions.
  3. Hooks should only be called inside React components. If you call them outside of a React component (like in a regular JavaScript file), they won't work.
  4. When using useEffect, if you're not setting an initial value, you should specify which value's change will trigger re-rendering. (If not set properly, you may run into an infinite loop in some cases.)

Thank you.

React + MobX
SPA 라이브러리인 React를 MobX state 관리 라이브러리와 함께 배워봅시다.