1

I am looking to have something run once when the react app first loads and only the one time. At first, one is inclined to make use of the useEffect hook:

  useEffect(() => {
    console.log("Effect hook.");
  }, []); 

The problem with this approach is that when I put it in my App component, the useEffect hook runs AFTER mounting. Subsequently, the following will fail because stuff won't be defined when the child component renders:

function App() {

  let stuff;

  // Define the supported configs on mount. This will only run at mount time.
  useEffect(() => {
    console.log("Effect hook.");
    stuff = getSomeStuff();
  }, []); 

  //

  console.log("About to return.");
  return (
    <div>
      <ComponentThatNeedsStuff stuff={stuff} />
    </div>
  );
}

and you will see the following printed:

About to return.
Effect hook.

If you only want the function getSomeStuff to run once but you need the stuff for child components, what is the best way to handle that?

Grant Curell
  • 1,321
  • 2
  • 16
  • 32
  • Does this answer your question? [componentWillMount for react functional component?](https://stackoverflow.com/questions/62091146/componentwillmount-for-react-functional-component) – Kenny Oct 29 '22 at 12:47
  • Not quite because I'm using state for other things - it's not clear to me how I would integrate the above. I may change how I do this entirely based on feedback coming in as it seems there are multiple alternatives, but `useMemo` as mentioned below in @Nicholas Tower's answer accomplished what I set out to do with this question. – Grant Curell Oct 29 '22 at 13:06

2 Answers2

3

Running code before render is usually a sign that you’re going against the grain of how React works.

const App = () => {
  const [stuff, setStuff] = useState();

  useEffect(() => {
    console.log("Effect hook.");
    setStuff(getSomeStuff());
  }, []); 


  return (
    <div>
      {stuff && <ComponentThatNeedsStuff stuff={stuff} />}
    </div>
  );
}
7.oz
  • 89
  • 2
  • 5
  • What is the correct way to do this? In my case, I have several supported configs I want to read into memory once and then pass to the child. Is there a better way to accomplish what I'm trying to do? – Grant Curell Oct 29 '22 at 12:45
  • I'm usually use NextJS and if that only configs i would define a .env file for that (react: https://create-react-app.dev/docs/adding-custom-environment-variables/) otherwise i declare the config outside the App component. – 7.oz Oct 29 '22 at 12:59
  • Now that I'm playing around with the options - the only downside to the main answer above is that in my live app I'm using routing. Apologies, I didn't include it in my snippit as I didn't think it would be relevant, but it seems like this doesn't work with routing because the element won't be defined? I'm a bit of a neophyte so I may be missing something. I'll check out the linked doc. – Grant Curell Oct 29 '22 at 13:12
1

This sounds like a job for useMemo. It lets you do a calculation during rendering, but then on later renders it can skip the calculation and reuse the previous value:

function App() {
  const stuff = useMemo(() => {
    return getSomeStuff();
  }, []);

  return (
    <div>
      <ComponentThatNeedsStuff stuff={stuff} />
    </div>
  );
}
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • I'll leave things open since there seems to be some good discussion and maybe I should be doing this differently but this was exactly the behavior I wanted. Thanks! Learned about a new hook today. – Grant Curell Oct 29 '22 at 13:03