0% completed
Functional and Class Components
On This Page
What the Class Needs
How React Uses Each One
Both Forms Can Hold Changing Data
Comparing the Two
Which One to Use
The same greeting can be written in two ways, and both put identical elements on the screen. One way uses a JavaScript function, and the other uses a JavaScript class. The first form is called a function component, which many articles also call a functional component, and the second is called a class component.
import { Text, View } from 'react-native'; function Greeting({ name }) { return ( <View> <Text>Hello, {name}!</Text> </View> ); } export default Greeting;
import { Component } from 'react'; import { Text, View } from 'react-native'; class Greeting extends Component { render() { return ( <View> <Text>Hello, {this.props.name}!</Text> </View> ); } } export default Greeting;
We rendered both with the name Maya and compared the results, and the two trees were the same:
View Text: Hello, Maya!
This is a second way of sorting components, separate from the built-in and custom groups in the previous lesson. That earlier question asks who wrote the component. This one asks how a custom component is written.
What the Class Needs
The class version has three requirements that the function does not have. It must extend Component, which comes from React, and older code often writes the same thing as React.Component. It must define a method named render, and it reads its values from this.props.
The render method is not optional. We wrote an empty class named NoRender. It failed as soon as React tried to display it, and React reported the cause first:
No `render` method found on the NoRender instance: you may have forgotten to define `render`. TypeError: instance.render is not a function
How React Uses Each One
The two forms also differ in what React does with them. To see the order, we added a console.log to each form and had a parent render it with the name Maya and then with the name Omar.
function GreetingFunction({ name }) { console.log(`function called, name=${name}`); return <Text>Hello, {name}!</Text>; } class GreetingClass extends Component { constructor(props) { super(props); console.log(`constructor called, name=${props.name}`); } render() { console.log(`render called, name=${this.props.name}`); return <Text>Hello, {this.props.name}!</Text>; } }
The console showed this:
function called, name=Maya function called, name=Omar constructor called, name=Maya render called, name=Maya render called, name=Omar
React calls a function component each time it needs the UI. For a class component, it creates one object the first time, then calls render on that same object each time.
Follow the name Omar in each column. In both forms it produces one new call, so the constructor runs only once, at the very start.
Both Forms Can Hold Changing Data
You may read that function components are only for static content and that classes are needed when data changes. That was true of old versions of React, and it is no longer true. A function can keep data between renders through useState, a function from React that the Hooks and State chapters explain. For now, read it as "a value that React remembers, plus a function that changes it".
import { useState } from 'react'; import { View, Text, Button } from 'react-native'; function TapCounter() { const [taps, setTaps] = useState(0); return ( <View> <Text>Taps: {taps}</Text> <Button title="Tap" onPress={() => setTaps(taps + 1)} /> </View> ); } export default TapCounter;
Here is the same counter as a class, which is what you will see in older projects:
import { Component } from 'react'; import { View, Text, Button } from 'react-native'; class TapCounter extends Component { state = { taps: 0 }; render() { return ( <View> <Text>Taps: {this.state.taps}</Text> <Button title="Tap" onPress={() => this.setState({ taps: this.state.taps + 1 })} /> </View> ); } } export default TapCounter;
We ran both and pressed the button twice in each. Both showed Taps: 2, so they behave the same way.
Comparing the Two
| Function component | Class component | |
|---|---|---|
| Written as | A function that returns JSX | A class that extends Component |
| Returns UI from | The function body | The render method, which is required |
| Reads its values from | The function's parameter | this.props |
| Keeps changing data with | useState | this.state and this.setState |
Which One to Use
Write function components. The React documentation recommends defining components as functions, and it does not recommend classes for new code. The function is shorter, and everything in the rest of this course that keeps data or reacts to changes uses functions.
Class components are still supported, so existing class code keeps working, and you need to read them when you work on an older project. There is also one case where a class is still required. An error boundary, a component that catches a rendering error in its children and shows a fallback screen, cannot currently be written as a function. Even then, you do not have to write the class yourself, because the react-error-boundary package provides one.
class ErrorBoundary extends Component { state = { failed: false }; static getDerivedStateFromError() { return { failed: true }; } render() { return this.state.failed ? <Text>Something went wrong.</Text> : this.props.children; } }
When a child of this class threw an error in our test, the screen showed Something went wrong. instead of crashing. You do not need this yet, and it is here only as the one exception to the rule.
Reading Progress
0%
On This Page
What the Class Needs
How React Uses Each One
Both Forms Can Hold Changing Data
Comparing the Two
Which One to Use