Home > Back-end >  Is the following form of functional components valid?
Is the following form of functional components valid?

Time:12-09

Pretty new to React here. Thus far, I've only been using components that either take no arguments or props. Then, I always render the component using the form <SomeComponent {...props}/>

However, I came across a situation where I didn't even realize that some of the functions I was creating were actually functional components since they were returning JSX. However, they were visibly different from the way I'm used to making and using components. It looked something like this:

  const MoneyExample = (category, amount) => {
    if (typeof amount !== "number" || typeof category !== "string") {
      return;
    }
    return (
      formatter.format(amount) !== "$0" && (
        <>
          <h4>{category.charAt(0).toUpperCase()   category.slice(1)}</h4>
          <p>{formatter.format(amount)}</p>
        </>
      )
    );
  };

and then rendering it inside another component using like this

{MoneyExample("Budget", someAmount)}

instead of the more common form

<MoneyExample budget={"Budget"} amount={someAmount} />

I've tried looking around for info, but I'm not even really sure how to phrase the question. Is this type of thing against React's principles or completely fine? Are there any other considerations or notable differences between these two? Sorry if this is obvious to some.

CodePudding user response:

{MoneyExample("Budget", someAmount)}

When you do this, MoneyExample is not being used as a component. It's being used as a helper function. The code inside MoneyExamples executes immediately, and then its return value is used. In contrast, the <MoneyExample version tells react you want a MoneyExample with certain props, but MoneyExample doesn't actually get called just yet (it usually gets called very soon after)

In very simple cases this will work ok, but as soon as you add in hooks you'll start running into trouble. As far as react can tell, those hooks are part of the component that's calling MoneyExample, not part of MoneyExample itself. You will therefore be forcing yourself to obey the rules of hooks, which means MoneyExample must be called exactly the same number of times on each render.

Additionally, doing it this way also means you can't make use of React.memo to skip rendering. The function must always execute, even if nothing changed.


In short: I recommend you stick to creating components that accept props, and then create elements using the JSX syntax.

const MoneyExample = ({ category, amount }) => {
  // ...
}
<MoneyExample budget={"Budget"} amount={someAmount} />

CodePudding user response:

you can't just return, but you can return null.

const MoneyExample = ({category, amount}) => {
  if (typeof amount === "number" || typeof category === "string") {
    const value = formatter.format(amount);
    if(value !== "$0") {
      return (
        <>
          <h4>{category.charAt(0).toUpperCase()   category.slice(1)}</h4>
          <p>{value}</p>
        </>
      );
    }
  }
  return null;
};

and you should use:

<MoneyExample budget={"Budget"} amount={someAmount} />

the include via function can have some strange behaviour on rerendering of components.

https://griffadev.medium.com/just-a-friendly-reminder-that-react-isnt-really-just-javascript-don-t-nest-functional-components-a6a822dddd

  • Related