javascriptreactjsreact-hooksfrontenduse-effect

How to trigger useEffects before render in React?


I have a prop being passed from a parent component to a child component which changes based on the user's input.

I want to trigger a data fetch in the child component when that prop changes before the child component is rendered. How can I do it?

I tried in the following manner by using useEffects(()=>{},[props.a, props.b]) but that is always called after the render. Please help!

import React, { useEffect, useState } from "react";
import "./styles.css";

export default function parentComponent() {
  const [inputs, setInputs] = useState({ a: "", b: "" });
  return (
    <>
      <input
        value={inputs.a}
        onChange={(event) => {
          const value = event.target.value;
          setInputs((prevState) => {
            return { ...prevState, a: value };
          });
        }}
      />
      <input
        value={inputs.b}
        onChange={(event) => {
          const value = event.target.value;
          setInputs((prevState) => {
            return { ...prevState, b: value };
          });
        }}
      />
      <ChildComponent a={inputs.a} b={inputs.b} />
    </>
  );
}

function ChildComponent(props) {
  const [isLoading, setIsLoading] = useState(true);
  const [data, setData] = useState({});

  useEffect(() => {
    console.log("updating new data based on props.a: " + props.a);
    setData({ name: "john " + props.a });
    return () => {};
  }, [props.a, props.b]);

  useEffect(() => {
    console.log("data successfully changed");
    console.log(data);
    if (Object.keys(data).length !== 0) {
      setIsLoading(false);
    }
    return () => {};
  }, [data]);

  function renderPartOfComponent() {
    console.log("rendering POC with props.a: " + props.a);
    return <div>data is: {data.name}</div>;
  }
  return (
    <div className="App">{isLoading ? null : renderPartOfComponent()}</div>
  );
}

In the console what I get is:

rendering POC with props.a: fe 
rendering POC with props.a: fe 
updating new data based on props.a: fe 
rendering POC with props.a: fe 
rendering POC with props.a: fe 
data successfully changed 
Object {name: "john fe"}
rendering POC with props.a: fe 
rendering POC with props.a: fe 

If you know how I can make the code more efficient, that would be a great help as well!

Here's the codesandbox link for the code: https://codesandbox.io/s/determined-northcutt-6z9f8?file=/src/App.js:0-1466


Solution

  • I found the solution by creating and maintaining state within the ChildComponent

    So, the order of processes was this: props modified -> render takes place -> useEffect block is executed.

    I found the workaround by simply instantiating a state within the childComponent and making sure that the props state is the same as the one in the child component before rendering, else it would just show loading... This works perfectly.