reactjsreact-hoc

Why does componentDidMount fires in a HOC where as componentDidUpdate does not fire?


I am following a reactjs tutorial on higher order components(HOC). I want a HOC to log props when props change.

import React, { useState } from 'react';

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentDidMount() {
      console.log("Component was mounted");
    }
    componentDidUpdate(prevProps) {
      console.log("Current props: ", this.props);
      console.log("Previous props: ", prevProps);
    }
    render() {
      // Wraps the input component in a container, without mutating it. Good!
      return <WrappedComponent {...this.props} />
    }
  }
}

class CustomDivElement extends React.Component{
  render(){
  return <div>{this.props.text}</div>
  }
}

function App(props) {
  const [text, setText] = useState("");
  const EnhancedComponent = logProps(CustomDivElement);
  return (
    <div tabIndex="0" className="App ui container">
      <input
      type="text"
      value={text}
      onChange={(e) => setText(e.target.value)} />
      <EnhancedComponent text={text} />
    </div>
  )
}

export default App

At first I thought it's because I am using a HOC. So I introduced another lifecycle method which is componentDidMount and it's firing. The componentDidUpdate is not firing, why is that?


Solution

  • Because you unmount the component on every render, the component doesn't get to componentDidUpdate lifecycle.

    function App(props) {
      // Remount on every render
      const EnhancedComponent = logProps(CustomDivElement);
      ...
    }
    

    Instead, when using HOC, or any other Component, you want to mount it once:

    // export default logProps(CustomDivElement)
    const EnhancedComponent = logProps(CustomDivElement);
    
    function App(props) {
      const [text, setText] = useState("");
      return (
        <div tabIndex="0" className="App ui container">
          <input
          type="text"
          value={text}
          onChange={(e) => setText(e.target.value)} />
          <EnhancedComponent text={text} />
        </div>
      )
    }