A Deep Dive into the React Native Component Lifecycle
If you are entering into the exciting domain of React native app development, understanding the internal operations of its components lifecycle is necessary. Just like a beating heart, this component lifecycle maintains the behaviour and flow of your application’s basic elements.
In this intuitive journey, we’ll dive into the deep investigation of the React Native Component lifecycle, including its stages – initialization, updates, and unmounting. By obtaining in-depth insights into how these components operate at each phase of the lifecycle, developers can boost performance, handle state modifications, and take required actions.
Let’s uncover the basics of React native app development framework to streamline your app development process!
What are React Lifecycle Methods?
Each phase has its own React class component. The properties or props that are acquired by a component instance when it is created and inserted into the DOM can now be accessed by using this. props function. The entire lifecycle “thing” starts at this stage.
Do keep in mind that a React component may NOT go through all of the phases. Without any updates or error handling, the component might be mounted and unmounted within the next minute.
A component’s lifecycle can be categorized into 4 parts:
- Mounting: In this phase, component instances are created and inserted into the DOM.
- Updating: In the updating phase, a react component is said to be born and it starts growing by receiving new updates.
- Unmounting: In this phase, a react component gets removed from the actual DOM.
- Error Handling: It is invoked when any error occurs while rendering the component.
Methods in React Native Component Lifecycle
1. Mounting
Below are the methods which get called when an instance of a component is created and inserted into the DOM.
A. Constructor()
First comes the constructor method, then mounting to the DOM, and finally rendering. Normally, you would initialize the state and attach event handlers inside the constructor method. This method is the first stage of the lifecycle and is only executed when it is explicitly declared; otherwise, use componentDidMount(). There is no need to create any side effects or subscriptions in this method.
1 2 3 4 5 6 7 8 9 10 11 |
constructor(props){ super(props); this.state = { message: 'hello world', } // this is our initial data } |
B. static getDerivedStateFromProps()
Despite of calling setState, GetDerivedStateFromProps returns an object with the updated state. Note that there are no unintended side effects to the function. Because GetDerivedStateFromProps may be called several times for just a single update, it is necessary to refrain from any negative effects. Since componentDidUpdate only executes once following a component update, consider using it as an alternative.
You can either return a null value or an object to make no changes to the component’s state:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
// ... static getDerivedStateFromProps(props, state) { return { message: 'updated msg', } } // or you can return null to make no update static getDerivedStateFromProps(props, state) { return null } // ... |
C. render()
The render method is the next lifecycle method called after the static getDerivedStateFromProps function. The render method must return a React Native component (JSX element) in order to render something, or null to render nothing. This step completes the rendered UI component.
Remember that the render function of the render method should be pure; therefore, refrain from attempting to use setState or interact with external APIs. It generates the same outcome every time it is used and doesn’t engage in any kind of interaction with the browser.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
render(){ return ( <View> <Text>{this.state.message}</Text> </View> ) } |
Learn How to integrate APIs in React native to enhance your app’s functionality.
D. ComponentDidMount()
Following the completion of render(), the component is mounted to the DOM and ComponentDidMount() is called immediately. When this method is called, a UI element has been rendered, without a doubt. Here, subscriptions (for example, timers) can be set up and a fetch request to the server can be made. Always consider that changing the state will cause a new instance of the render() method to be called without taking into account the previous state. Before calling this function, we are using the virtual DOM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// good place to call setState here componentDidMount(){ this.setState({ message: 'i got changed', }); } --- // or to make request to the server componentDidMount() { fetch('https://api.mydomain.com') .then(response => response.json()) .then(data => this.setState({ message: data.message })); } |
Second use case: componentDidMount() is a great place to retrieve data from a server, call our setState() method to change the application’s state, and render() the newly updated information.
2. Updating
Whenever any change occurs inside the component or parent component, for instance, when the prop or state are changed, the component may require to be re-rendered. If simply put, the component is updated.
So, which lifecycle methods are called while the component is is updated? Let’s have a look!
A. static getDerivedStateFromProps()
First, the static getDerivedStateFromProps function is called. That’s the first method to be used. It’s important to keep in mind that, this method is used during both mounting and updating phases.
B. shouldComponentUpdate()
When the state or props change, you want a component to re-render by default or even in most situations. But there is some control over this behavior that you have.
React decides whether or not to update a component at this moment.
Upon a change in the state or props, you can control whether the component is re-rendered or not within this lifecycle method by returning a boolean. Usually, performance optimization measures are implemented using this lifecycle method.
C. render()
Depending on the returned value from the shouldComponentUpdate method, which by default, returns true, a render is called right away after the shouldComponentUpdate method has been called.
D. getSnapshotBeforeUpdate(prevProps, prevState)
getSnapshotBeforeUpdate() is called immediately following the render method and before the most recent rendered output is committed, such as to the DOM.
Although it has a common use case in React, it serves no purpose in React Native. To sum up, if you are using React to create a chat application, you can use this method to determine the scroll size and scroll to the bottom as new messages are received. Simply use the onContentSizeChange prop for ScrollView in React Native. A component with auto-scroll functionality might resemble this:
1 2 3 4 5 6 |
<ScrollView onContentSizeChange={()=>{this.scrollViewRef.scrollToEnd();}} ref={(ref) => this.scrollViewRef = ref} > <Chats chatList={this.state.chatList} /> </ScrollView> |
To keep you informed of new messages, ScrollView is automatically scrolled to the bottom when chatList is updated with new messages.
E. componentDidUpdate()
The componentDidUpdate() method is called immediately as soon as the update occurs. This approach is not utilized in the initial render. As long as you compare the current props to previous props, this is a ideal point to make network requests as well (e.g., a network request may not be required if the props have not changed).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
componentDidUpdate(preProps) { if(prevProps.selectedState !== this.props.selectedState){ fetch('https://pathToApi.com') .then(resp => resp.json()) .then(respJson => { // do what ever you want with your `response` this.setState({ isLoading: false, data: respJson, }); }) .catch(err => { console.log(err) }) } } |
3. Unmounting
A. componentWillUnmount()
Just before a component is unmounted and destroyed, componentWillUnmount() is called. Execute any necessary cleanup in this method, including invalidating timers, cancelling network requests, and removing any subscriptions that componentDidMount() may have created.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// e.g add event listener componentDidMount() { el.addEventListener() } // e.g remove event listener componentWillUnmount() { el.removeEventListener() } |
Typical uses of componentDidMount with componentWillUnmount –
Since the component won’t ever be re-rendered, you shouldn’t call setState() in componentWillUnmount(). It is impossible to remount a component instance once it has been unmounted.
4. Error handling
Imagine writing a code for a mobile app development process without any mistakes! However, this is a more impractical objective. In real life, mistakes are common; sometimes we recognize them, other times we don’t. Thus, in this section, you will learn some basic error-handling techniques to help you avoid making the same mistakes.
Let’s add a straightforward component to the demo app to detect mistakes. To do this, we’ll make a brand-new component called ErrorBoundary.
Here’s the most basic implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import React, { Component } from 'react'; class ErrorBoundary extends Component { state = { hasError: false, }; render() { return this.props.children; } } export default ErrorBoundary; |
A. static getDerivedStateFromError()
This method is always called first and receives the error as an argument whenever a descendant component throws an error.
The state of the component is updated using whatever value is returned by this method.
Let’s update the ErrorBoundary component, using this lifecycle method.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
import React, { Component } from "react"; class ErrorBoundary extends Component { state = { hasError: false, }; static getDerivedStateFromError(error) { console.log(`Error log from getDerivedStateFromError: ${error}`); return { hasError: true }; } render() { if(this.state.hasError) { return <Text> Something went wrong :( </Text> } return this.props.children; } } export default ErrorBoundary; |
From now on, whenever a descendant component throws an error, the error will be console.log(error), and the getDerivedStateFromError method will return an object. This will be used to update the hasError:true state of the ErrorBoundary component.
Note: side effects are not allowed because getDerivedStateFromError() is called during the “render” stage. Use componentDidCatch() in those situations instead.
B. componentDidCatch(error, info)
Additionally, after a descendant component throws an error, the componentDidCatch method is invoked. In addition to the error that is thrown, it also passes another argument that contains further details about the mistake. You can send the error or information obtained using this technique to an outside logging service. componentDidCatch, as opposed to getDerivedStateFromError, supports side effects
1 2 3 4 5 6 7 |
componentDidCatch(error, info) { logComponentStackToMyService(info.componentStack); // logToExternalService may make an API call. } |
Let’s update the ErrorBoundary component to use the componentDidCatch method:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { hasError: true }; } componentDidCatch(error, info) { // Example "componentStack": // in ComponentThatThrows (created by App) // in ErrorBoundary (created by App) // in div (created by App) // in App logComponentStackToMyService(info.componentStack); } render() { if (this.state.hasError) { // You can render any custom fallback UI return <Text>Something went wrong.</Text>; } return this.props.children; } } |
Additionally, since ErrorBoundary is only able to handle errors from descendant components, we’ll either have the component display whatever is passed to it as children or, in the event that something went wrong, display a default error UI.
The Final Outline
Thus, in order to create high-performance, effective, and reliable mobile applications, it is crucial to comprehend the React Native component lifecycle. The component lifecycle is a series of activities that take place from the moment of a component’s development until its demise. Every event offers the chance to carry out particular actions, such as obtaining data, changing the state, or depleting resources. In order to create seamless user experiences, Hire react native app developers who are experienced with component lifecycle methods and how to leverage them.
DianApps is a fantastic option if you’re searching for a professional React Native app development company. DianApps can assist you in creating cutting-edge mobile applications that make use of all of React Native’s features thanks to its staff of skilled developers. DianApps provides complete React Native development services, from UI design to API integration, to help you meet your mobile app development objectives. For more information on how DianApps can assist you in creating your upcoming React Native mobile app, get in touch with them right away.