Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional Component: Write functions inside or outside the component?

I often wrote functional components following a 'Class architecture' where all my function that concern the component are written inside of it like a method in a class.

For example, I have here a function counterAsFloat that is related to the Counter component. As you see I just wrote it inside of the component:

export default function Counter() {   const [counter, setCounter] = React.useState(0);    const counterAsFloat = () => {     return counter.toFixed(2);   };    return (     <div className="counter">       <h1>{counterAsFloat()}</h1>       <button onClick={() => setCounter(counter + 1)}>         Increment       </button>     </div>   ); } 

But actually I could also just declare the function outside the component and use it with a parameter:

const counterAsFloat = (counter) => {    return counter.toFixed(2); };  export default function Counter() {   const [counter, setCounter] = React.useState(0);    return (     <div className="counter">       <h1>{counterAsFloat(counter)}</h1>       <button onClick={() => setCounter(counter + 1)}>         Increment       </button>     </div>   ); } 

So are there any pros or cons to write the functions outside the functional component?

like image 846
johannchopin Avatar asked Jul 11 '20 10:07

johannchopin


People also ask

How do you create a function inside a functional component?

We can create a functional component to React by writing a JavaScript function. These functions may or may not receive data as parameters. In the functional Components, the return value is the JSX code to render to the DOM tree. Example: Program to demonstrate the creation of functional components.

How do you write a function inside a functional component in React?

Have you wondered how to create a component in React? To answer, it is as simple as creating a function returning an HTML-like syntax. import React from 'react'; function Counter({n}) { return ( <div>{n}</div> ); } export default Counter; Now let's see what happened in the code above.

Can stateless components have functions?

A stateless function component is a typical React component that is defined as a function that does not manage any state. There are no constructors needed, no classes to initialize, and no lifecycle hooks to worry about. These functions simply take props as an input and return JSX as an output.

How do you call a function inside a React?

To call a function inside another function, define the inner function inside the outer function and invoke it. When using the function keyword, the function gets hoisted to the top of the scope and can be called from anywhere inside of the outer function.


2 Answers

This question is pretty opinion-based but there are few notes that you need to think about.

Declaring the function outside of scope is foremost for readability and reusability.

// Reuse logic in other components const counterAsFloat = (counter) => {    return counter.toFixed(2); };  // If Counter has complex logic, you sometimes want to compose it // from functions to make it more readable. export default function Counter() {   ...    return (...); } 

One can argue that the first option is less performant because you declare the function on every render:

export default function Counter() {   ...    // declare the function on every render   const counterAsFloat = () => {     return counter.toFixed(2);   };    return (...); } 

Such case is premature optimization. Check out JavaScript closures performance which relates to this.

Note that in this specific case, inlining the function is much better approach.

export default function Counter() {   ...   return (     <div>       <h1>{counter.toFixed(2)}</h1>       ...     </div>   ); } 
like image 88
Dennis Vash Avatar answered Sep 18 '22 16:09

Dennis Vash


While you could want to use outside functions for organization or reusability, it stills seems to go against the structure of functional components, at least for one reason: in functional components, states are immutable. So they normally are constants. And while your 2 functions seem to be somewhat similar, they differ greatly, precisely regarding this specific feature. Take for example this code:

const a = 2; function increment(){     return ++a; } increment(); 

This is obviously forbidden, you cannot change a constant.

Write it differently:

 const a = 2;  function increment(a){     return ++a;  }  increment(a); 

The last one is allowed. It won't give the result you expect, at least looking at it rapidly, but it'll compile and won't have any runtime error.

Transpose this to your example. Let's say that you begin by wanting to simply output yourt counter with toFixed(2), so you create an outside function. But then afterwards you decide that over 5 you want to reset the counter. So you do this:

const counterAsFloat = (counter) => {     if(counter > 5){        counter = 0;     }     return counter.toFixed(2); }; 

This is going to be allowed, will compile and run. It' won't give the expected result, but it won't be obvious. The inside function could work:

const counterAsFloat = () => {     if(counter > 5){        counter = 0;     }     return counter.toFixed(2); }; 

But because in the inside scope counter is a constant you're going to have a compile error or at least a runtime error. That you can quickly fix by replacing counter = 0; by setCounter(0); which is the proper way to handle this requirement.

So in the end, by staying inside your component, it is clearer what the state values are and you're going to have clearer feedback on forbidden manipulations that may be be less obvious with outside functions.

See example with outside function, it is working but doesn't give you the expected result:

const counterAsFloatOutside = (counter) => {     if(counter > 5){         counter = 0;     }     return counter.toFixed(2);  };      function Counter() {   const [counter, setCounter] = React.useState(0);       return (     <div className="counter">       <h1>{counterAsFloatOutside(counter)}</h1>       <button onClick={() => setCounter(counter + 1)}>         Increment       </button>     </div>        ); } ReactDOM.render(React.createElement(Counter, null), document.body);
 <script type="text/javascript" src="https://unpkg.com/react@16/umd/react.development.js"></script> <script type="text/javascript" src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

With the inside function, it's just not working, which in this case, is preferable. Working with any compiling tool will even give you the error upfront, which is a huge advantage:

     function Counter() {   const [counter, setCounter] = React.useState(0);   const counterAsFloat = () => {     if(counter > 5){         counter = 0;     }     return counter.toFixed(2);  };    return (     <div className="counter">       <h1>{counterAsFloat()}</h1>       <button onClick={() => setCounter(counter + 1)}>         Increment       </button>     </div>        ); } ReactDOM.render(React.createElement(Counter, null), document.body);
<script type="text/javascript" src="https://unpkg.com/react@16/umd/react.development.js"></script> <script type="text/javascript" src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
like image 38
Julien Grégoire Avatar answered Sep 20 '22 16:09

Julien Grégoire