React Hooks allows us to write Stateful functional Components by using functions called hooks provided by React and you can create your own custom Hooks that you can share across many components.

In this article we are going to look into some of the different hooks and see how they compare to traditional Class based components.

We are gonna look at the three basic and most used hooks useState,useEffect and useContext.

Let’s get started but before we start I hope you have a bit of experience with React and Component lifecycles.

useState()

So to get started with things we’ll do something simple use of useState() for Creating and mutating state.


class App extends React.Component{
  contructor(props){
    super(props);
    this.name = "Yogesh";
    this.handleNameChange= this.handleNameChange.bind(this);
    // ✅ We have to bind 'this' for method to work.
  }
  handleNameChange(event){
    this.setState(name: event.target.value);
  }

  render(){
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange} />
      </div>
    )
  }
}

In the above code block we contructed a simple class based Stateful component with name property in it. And also a input tag with onChnage handler to mutate the state value.

Now let’s try the above example with Hooks.

function App() {
  const [name, setName] = useState("Yogesh");
  // Here we declare the state and pass a initial value.

  function handleNameChange(event) {
    setName(event.target.value);
  }
  return (
    <div>
      <input
        type="text"
        value={this.state.name}
        onChange={this.handleNameChange}
      />
    </div>
  );
}

As you can see using hooks not only made our code cleaner but easier to understand. You can use as many as hooks you want in a single functional component. Just make sure you are not calling hooks in conditional, loops or nested body.

function App(props) {
  if (props.isValid) {
    const [name, setName] = useState("Yogesh");
    // ❌ You can't use hooks in conditional statement
  }
  const [name, setName] = useState("Yogesh");
  // ✔ Use Hooks in function body only.

  function handleNameChange(event) {
    setName(event.target.value);
  }
  return (
    <div>
      <input
        type="text"
        value={this.state.name}
        onChange={this.handleNameChange}
      />
    </div>
  );
}

Note: Hook can only be called at top level function body because react keeps tracks of all hooks calls in component to determine which hook to run when condition is met so putting hook into condtional will break the call track.

You can use multiple useState inside a single component.

function App(props) {
  const [name, setName] = useState("Yogesh");
  const [state, setState] = useState({ isCool: true });

  function handleNameChange(event) {
    setName(event.target.value);
  }
  return (
    <div>
      <input
        type="text"
        value={this.state.name}
        onChange={this.handleNameChange}
      />
    </div>
  );
}

I think that’s it for useState, onto the next one.

useEffect()

“The Effect Hook lets you perform side effects in function components” - Reactjs.org

Well, Let’s break it down what does that means. In functional paradigm a function sould always be Pure Function with out an side effects. Means output of a function should always be the same given the same input everytime.

Before React Hooks function components were stateless that means you cannot mutate or create state inside that component and since you cannot change anything that component will always render same given the same props and that’s why they were called functional components. But now with hooks you can perform side Effects without breaking too much functional principles.

So useEffect() is replacement for componentDidMount() and componentDidUpdate() in component lifecycle.

Let’s check with an example as I think that’s best way to understand. Will use the above example.

class App extends React.Component{
  contructor(props){
    super(props);
    this.name = "Yogesh";
  }

  handleNameChange = (event) => {
    this.setState(name: event.target.value);
  }

  componentDidMount(){
    // This method runs when component first mounts
    console.log('Run this when Component mounts');
  }

  componentDidUpdate(){
    // This method runs whenever props or state
    // changes in component
    console.log('Run this when Component updates');
  }

  render(){
    return (
      <div>
        <input
          type="text"
          value={this.state.name}
          onChange={this.handleNameChange} />
      </div>
    )
  }
}

This is the Class way of to perform updates whenever props or state changes.

Now let’s see how we can perform those lifecycles in functional component using Hooks.

function App(props) {
  const [name, setName] = useState("Yogesh");

  useEffect(() => {
    console.log("Run this when Component mounts");
  }, []); // This hook will only run once when component mounts

  function handleNameChange(event) {
    setName(event.target.value);
  }
  return (
    <div>
      <input
        type="text"
        value={this.state.name}
        onChange={this.handleNameChange}
      />
    </div>
  );
}

useEffect() takes function callback as an arguments. Additionally you can also provide Hooks dependency to determine how hook will perform.

Now let’s try to implement componentDidUpdate using Hooks. To execute something when component updates using useEffect hook we have to provide dependencies to hook.

Whenever that dependency changes it will run the hooks callback.

function App(props) {
  const [name, setName] = useState("Yogesh");

  useEffect(() => {
    console.log("Run this when Props changes");
  }, [props]); // this is where we provide all the dependencies

  function handleNameChange(event) {
    setName(event.target.value);
  }
  return (
    <div>
      <input
        type="text"
        value={this.state.name}
        onChange={this.handleNameChange}
      />
    </div>
  );
}

In the above snippet useEffect will run everytime props changes. And we can provide multiple dependencies since it’s an Array.