React Function Components, also known as React Functional Components , are the status quo for writing modern React applications. In the past, there have been various React Component Types , but with the introduction of React Hooks itâs possible to write your entire application with just functions as React components.
This in-depth guide shows you everything about React Function Components, which are basically just JavaScript Functions being React Components which return JSX (Reactâs Template Syntax), so that after you have read this tutorial you should be well prepared to implement modern React applications with them.
Letâs start with a simple example of a Functional Component in React defined as App component which returns JSX:
Thatâs already the essential React Function Component syntax . The definition of the component happens with just a JavaScript function which returns JSX, Reactâs syntax for defining a mix of HTML and JavaScript whereas the JavaScript is used with curly braces within the HTML. In our case, we render a variable called greeting , which is defined in the componentâs function body, and is returned as HTML headline in JSX.
Now, if you want to render a React Component inside a Function Component, you define another component and render it as React element with JSX:
Basically you have a function as a Child Component now. Defining React Components and rendering them within each other makes composition in React possible. You can decide where to render a component and how to render it.
Letâs learn about a React Function Component with props. In React, props are used to pass information from component to component. If you donât know about props in React, cross-read the linked article. Essentially props in React are always passed down the component tree:
Props are the React Function Componentâs parameters. Whereas the component can stay generic, we decide from the outside what it should render (or how it should behave). When rendering a component (e.g. Headline in App component), you can pass props as HTML attributes to the component. Then in the Function Component the props object is available as argument in the function signature.
Since props are always coming as object, and most often you need to extract the information from the props anyway, JavaScript object destructuring comes in handy. You can directly use it in the function signature for the props object:
Note: If you forget the JavaScript destructuring and just access props from the componentâs function signature like function Headline(value1, value2) { ... } , you may see a âprops undefinedâ-messages. It doesnât work this way, because props are always accessible as first argument of the function and can be destructured from there: function Headline({ value1, value2 }) { ... } .
If you want to learn more tricks and tips about React props, again check out the linked article from the beginning of this section. There you will learn about cases where you donât want to destructure your props and simply pass them to the next child component with the â¦syntax known as spread operator.
With the introduction of JavaScript ES6, new coding concepts were introduced to JavaScript and therefore to React . For instance, a JavaScript function can be expressed as lambda ( arrow function ).
Thatâs why a Function Component is sometimes called Arrow Function Component or Arrow Function Expression Component (or rarely Lambda Function Component).
Letâs see our refactored React Component with an Arrow Function Expression:
Both React Arrow Function Components use a function block body now. However, the second component can optionally be made more lightweight with a concise body for the function, because it only returns the output of the component without doing something else in between. When leaving away the curly braces, the explicit return becomes an implicit return and can be left out as well:
When using arrow functions for React components, nothing changes for the props. They are still accessible as arguments as before. Itâs a React Function Component with ES6 Functions expressed as arrows instead of ES5 Functions which are the more default way of expressing functions in JS.
Note: If you run into a âReact Component Arrow Function Unexpected Tokenâ error, make sure that JavaScript ES6 is available for your React application. Normally when using modern tooling this should be given, otherwise, if you set up the project yourself, Babel is enabling ES6 and beyond features for your React application .
Every component we have seen so far can be called Stateless Function Component . They just receive an input as props and return an output as JSX: (props) => JSX . The input, only if available in form of props, shapes the rendered output. These kind of components donât manage state and donât have any side-effects (e.g. accessing the browserâs local storage).
People call them Functional Stateless Components , because they are stateless and expressed by a function. However, React Hooks made it possible to have state in Function Components.
React Hooks made it possible to use state (and side-effects) in Function Components. Finally we can create a React Function Component with state! Letâs say we moved all logic to our other Function Component and donât pass any props to it:
So far, a user of this application has no way of interacting with the application and thus no way of changing the greeting variable. The application is static and not interactive at all. State is what makes React components interactive; and exciting as well. A React Hook helps us to accomplish it:
The useState hook takes an initial state as parameter and returns an array which holds the current state as first item and a function to change the state as second item. We are using JavaScript array destructuring to access both items with a shorthand expression. In addition, the destructuring lets us name the variables ourselves.
Letâs add an input field to change the state with the setGreeting() function:
By providing an event handler to the input field, we are able to do something with a callback function when the input field changes its value. As argument of the callback function we receive a synthetic React event which holds the current value of the input field. This value is ultimately used to set the new state for the Function Component with an inline arrow function. We will see later how to extract this function from there.
Note: The input field receives the value of the component state too, because you want to control the state (value) of the input field and donât let the native HTML elementâs internal state take over. Doing it this way, the component has become a controlled component .
Note: If you want to use Reactâs Context in Function Components, check out Reactâs Context Hook called useContext for reading from Reactâs Context in a component.
In the previous example you have used an onChange event handler for the input field. Thatâs appropriate, because you want to be notified every time the internal value of the input field has changed. In the case of other HTML form elements, you have several other React event handlers at your disposal such as onClick, onMouseDown, and onBlur.
Note: The onChange event handler is only one of the handlers for HTML form elements. For instance, a button would offer an onClick event handler to react on click events.
So far, we have used an arrow function to inline the event handler for our input field. What about extracting it as standalone function inside the component? It would become a named function then:
We have used an arrow function to define the function within the component. If you have used class methods in React Class Components before, this way of defining functions inside a React Function Component is the equivalent. You could call it the âReact Function Component Methodsâ-equivalent to class components. You can create or add as many functions inside the Functional Component as you want to act as explicit event handlers or to encapsulate other business logic.
Everything happens in our Child Function Component. There are no props passed to it, even though you have seen before how a string variable for the greeting can be passed from the Parent Component to the Child Component. Is it possible to pass a function to a component as prop as well? Somehow it must be possible to call a component function from the outside! Letâs see how this works:
Thatâs all to it. You can pass a function to a Child Component and handle what happens up in the Parent Component. You could also execute something in between in the Child Component (Headline component) for the onChangeHeadline function â like trimming the value â to add extra functionality inside the Child Component. Thatâs how you would be able to call a Child Componentâs function from a Parent Component.
Letâs take this example one step further by introducing a Sibling Component for the Headline component. It could be an abstract Input component:
I find this is a perfect yet minimal example to illustrate how to pass functions between components as props; and more importantly how to share a function between components. You have one Parent Component which manages the logic and two Child Components â which are siblings â that receive props. These props can always include a callback function to call a function in another component. Basically thatâs how itâs possible to call a function in different components in React.
Itâs shouldnât happen often, but I have heard people asking me this question. How would you override a componentâs function? You need to take the same approach as for overriding any other passed prop to a component by giving it a default value:
You can assign the default value in the function signature for the destructuring as well:
All of these approaches can be used to define default props (in this case a default function), to be able to override it later from the outside by passing an explicit prop (e.g. function) to the component.
Another special case may be an async function in a React component. But there is nothing special about it, because it doesnât matter if the function is asynchronously executed or not:
The function executes delayed without any further instructions from your side within the component. The component will also rerender asynchronously in case props or state have changed. Take the following code as example to see how we set state with a artificial delay by using setTimeout :
Also note that we are using a callback function within the setCount state function to access the current state. Since setter functions from useState are executed asynchronously by nature, you want to make sure to perform your state change on the current state and not on any stale state.
Experiment: If you wouldnât use the callback function within the State Hook, but rather act upon the count variable directly (e.g. setCount(count + 1) ), you wouldnât be able to increase the value from 0 to 2 with a quick double click, because both times the function would be executed on a count state of 0.
Note: If you have used React Class Components before, you may be used to lifecycle methods such as componentDidMount, componentWillUnmount and shouldComponentUpdate. You donât have these in Function Components, so letâs see how you can implement them instead.
First of all, you have no constructor in a Function Component. Usually the constructor would have been used in a React Class Component to allocate initial state. As you have seen, you donât need it in a Function Component, because you allocate initial state with the useState hook and set up functions within the Function Component for further business logic:
Second, there is the mounting lifecycle for React components when they are rendered for the first time. If you want to execute something when a React Function Component did mount , you can use the useEffect hook:
If you try out this example, you will see the count 0 and 1 shortly displayed after each other. The first render of the component shows the count of 0 from the initial state â whereas after the component did mount actually, the Effect Hook will run to set a new count state of 1.
Itâs important to note the empty array as second argument for the Effect Hook which makes sure to trigger the effect only on component load (mount) and component unload (unmount).
Experiment: If you would leave the second argument of the Effect Hook empty, you would run into an infinite loop of increasing the count by 1, because the Effect Hook always runs after state has changed. Since the Effect Hook triggers another state change, it will run again and again to increase the count.
Every time incoming props or state of the component change, the component triggers a rerender to display the latest status quo which is often derived from the props and state. A render executes everything within the Function Componentâs body.
Note: In case a Function Component is not updating properly in your application, itâs always a good first debugging attempt to console log state and props of the component. If both donât change, there is no new render executed, and hence you donât see a console log of the output in the first place.
If you want to act upon a rerender, you can use the Effect Hook again to do something after the component did update:
Now every time the Function Component rerenders, the count is stored into the browserâs local storage. Every time you fresh the browser page, the count from the browserâs local storage, in case there is a count in the storage, is set as initial state.
You can also specify when the Effect Hook should run depending on the variables you pass into the array as second argument. Then every time one of the variables change, the Effect Hook runs. In this case it makes sense to store the count only if the count has changed:
By using the second argument of the Effect Hook with care , you can decide whether it runs:
React Class Components offered the possibility to decide whether a component has to rerender or not. It was achieved by using the PureComponent or shouldComponentUpdate to avoid performance bottlenecks in React by preventing rerenders . Letâs take the following extended example:
In this case, every time you type something in the input field, the App component updates its state, rerenders, and rerenders the Count component as well. React memo â which is one of Reactâs top level APIs â can be used for React Function Components to prevent a rerender when the incoming props of this component havenât changed:
Now, the Count component doesnât update anymore when the user types something into the input field. Only the App component rerenders. This performance optimization shouldnât be used as default though. I would recommend to check it out when you run into issues when the rerendering of components takes too long (e.g. rendering and updating a large list of items in a Table component).
Eventually you will separate components into their own files. Since React Components are functions (or classes), you can use the standard import and export statements provided by JavaScript. For instance, you can define and export a component in one file:
And import it in another file:
Note: If a Function Component is not defined, console log your exports and imports to get a better understanding of where you made a mistake. Maybe you used a named export and expected it to be a default export.
If you donât care about the component name by defining the variable, you can keep it as Anonymous Function Component when using a default export on the Function Component:
However, when doing it this way, React Dev Tools cannot identify the component because it has no display name. You may see an Unknown Component in your browserâs developer tools.
A React Ref should only be used in rare cases such as accessing/manipulating the DOM manually (e.g. focus element), animations, and integrating third-party DOM libraries (e.g. D3). If you have to use a Ref in a Function Component, you can define it within the component. In the following case, the input field will get focused after the component did mount:
Often you want to pass a ref from a Parent Component down to a Child Function Component, for example to measure a childâs DOM node or to focus an input field from the outside. As of React 19, ref is just a regular prop, so you can pass it down and destructure it like any other prop:
Before React 19, function components could not receive a ref directly. You had to wrap the component in forwardRef to forward the ref down to the underlying DOM node. You will still encounter this pattern in older codebases, so itâs worth recognizing:
There are a few other things you may want to know about React Refs, so check out this article: How to use Ref in React or the official React documentation .
PropTypes can be used for React Class Components and Function Components the same way. Once you have defined your component, you can assign it PropTypes to validate the incoming props of a component:
Note that you have to install the standalone React prop-types , because it has been removed from the React core library a while ago. These days Iâd recommend using TypeScript instead of prop-types, which is shown in the next section.
In addition, there used to be default props for a Function Component. React 19 removed defaultProps for function components entirely, so prefer JavaScript default parameters (e.g. ({ headline = 'Hello Component' }) ) or TypeScript instead. Here is the old API for the sake of completeness, in case you still see it in an older code base:
However, if you really want to go all-in with strongly typed components in React, you have to check out TypeScript which is briefly shown in the next section.
If you are looking for a type system for your React application, you should give TypeScript for React Components a chance. A strongly typed language like TypeScript comes with many benefits for your developer experience ranging from IDE support to a more robust code base. You may wonder: How much different would a React Function Component with TypeScript be? Check out the following typed component:
It only defines the incoming props as types. However, most of the time type inference just works out of the box. For instance, the use State Hook from the App component doesnât need to be typed, because from the initial value the types for greeting and setGreeting are inferred.
If you want to know how to get started with TypeScript in React, check out this comprehensive cheatsheet ranging from TypeScript setup to TypeScript recipes . Itâs well maintained and my go-to resource to learn more about it.
This section will not present you any performance benchmark for Class Components vs Functional Components, but a few words from my side about where React may go in the future.
Since React Hooks have been introduced in React, Function Components are not anymore behind Class Components feature-wise. You can have state, side-effects and lifecycle methods in React Function Components now. Thatâs why I strongly believe React will move more towards Functional Components, because they are more lightweight than Class Components and offer a sophisticated API for reusable yet encapsulated logic with React Hooks.
For the sake of comparison, check out the implementation of the following Class Component vs Functional Component:
If you are interested in moving from Class Components to Function Components, check out this guide: A migration path from React Class Components to Function Components with React Hooks . However, there is no need to panic because you donât have to migrate all your React components now. Maybe itâs a better idea to start implementing your future components as Function Components instead.
The article has shown you almost everything you need to know to get started with React Function Components. If you want to dig deeper into testing React Components for instance, check out this in-depth guide: Testing React Components . Anyway, I hope there have been a couple of best practices for using Functional Components in React as well. Let me know if anything is missing!