ComponentDidUpdate Inside HOC is not being logged when input value Changes in Container

Viewed 137
import React, { useEffect, useState } from "react";
function logProps(WrappedComponent) {
    return class extends React.Component {
        componentDidUpdate(prevProps) {
        console.log("inside componentDidUpdate");
       }
        componentDidMount() {
            console.log("insideComponentDidMount");
        }
        render() {
            return <WrappedComponent {...this.props} />;
        }
     };
  }
const Container = (props) => {
    const [name, setName] = useState("");
    const handleInputChange = (value) => {
    setName(value);
    };
   return (
      <React.Fragment>
          <input value={name} onChange={(e) => handleInputChange(e.target.value)} />
      </React.Fragment>
       );
   };

export default logProps(Container);

Here the container component is wrapped inside the logProps HOC. I want to fire the component Did Update function once the input changes. I have used the same HOC as described in the official react docs.

1 Answers

There are lots of things to explain here

  1. Components are the dummy(stateless) or smart(stateful)
  2. Components will render either if props changes or state ()

Let's start from top to bottom respecting hierarchy

  1. HOC component renders 2.componentDidMount fires
  2. you can type in your child input now
  3. you change the value
  4. handleInputChange is fired
  5. setName is now called with a new value
  6. Container component re-renders duo to ()

We don't expect the HOC to update now, cause nothing fancy happened to it till now. If you want to call componentDidUpdate in each character change you must pass props from the logProps(Component) parent

something like this

import React, { useEffect, useState } from "react";
function logProps(WrappedComponent) {
    return class extends React.Component {
        componentDidUpdate(prevProps) {
        console.log("inside componentDidUpdate");
       }
        componentDidMount() {
            console.log("insideComponentDidMount");
        }
        render() {
            return <WrappedComponent {...this.props} />;
        }
     };
  }
const Container = ({name, handleInputChange}) => {
   
   return (
      <React.Fragment>
          <input value={name} onChange={(e) => handleInputChange(e.target.value)} />
      </React.Fragment>
       );
   };

export default logProps(Container);

// parent.js
const Parent = () => {
  const [name, setName] = useState("");
  return <LogPropsContainer handleInputChange={setName} name={name} />
}

Now you will see the log in every character change codesandbox

New Hook version of the logged life cycle

it is convenient to start HOC with with keyword

const withLogger = (Component) => {
  function HOC(props) {
    useEffect(() => {
      console.log("component did mount", { CDM: props });
      // eslint-disable-next-line
      return () => {
        console.log("component did unmount", { CDUM: props });
      };
    }, []);

    useEffect(() => {
      console.log("component did update", { CDU: props });
      return () => {
        console.log("component did update rerender", { rerender: props });
      };
    });

    return <Component {...props} />;
  };

  // rename component for better debuging
  if (process.env.NODE_ENV !== 'production') {
   const name = Component && (Component.displayName || Component.name)
   HOC.displayName = `Logger(${name || 'Anonymous' })`
  }
};
Related