Over the years ReactJS has gone through many changes by introducing new features and by deprecating the old ones. As of this article’s writing, the current version of React is 18.2.0.
A few significant new features that have been introduced in React from its version 16 to 18 are:-
- Rewriting of React’s Fiber Architecture: A complete rewrite of React’s core algorithm is done that improves performance and also enables new features like asynchronous rendering and error boundaries
- Addition of new Context API: A new API is added for passing data through the component tree without having to pass props down manually
- Introduction to Error Boundaries: A new feature is introduced that allows you to handle errors gracefully in your components
- Changes in React Lifecycle: Several lifecycle methods were deprecated in favor of new methods, such as componentWillMount() -> UNSAFE_componentWillMount()
- Introduction to React Hooks: A new way of writing stateful logic in functional components is introduced that makes it easier to reuse and test code
- Addition of React Strict Mode: A new feature called ‘strict mode’ is introduced that helps you identify deprecated patterns in your code and also provides feedback without impacting the production build
- Addition of Server Side Rendering (SSR): A new feature is added that allows React to render on the server-side for improved performance and SEO
- Introduction of new features such as Suspense, Concurrency, Automatic Batching, etc.
The “React Strict Mode” is a sort of passive debugging feature introduced in 2018 in React version 16.3 to help you write better React code.
In this article we will discuss the need for ‘React Strict Mode’; how different is ‘React Strict Mode’ from exception handling and debugging techniques; features and benefits of using ‘React Strict Mode’ in your React software projects.
Introduction
‘Strict Mode’ in React assists developers in adhering to the latest coding practices by identifying deprecated patterns and by providing feedback during the development.
By using ‘React Strict Mode’ you can catch potential issues earlier in the development process by performing additional checks and warnings that are not done in the production build.
‘React Strict Mode’ highlights the use of unsafe lifecycle methods, identifies side effects, and catches errors and warnings that might go unnoticed during development.
Also, ‘React Strict Mode’ encourages the use of recommended patterns and best practices, leading to cleaner and maintainable code.
‘React Strict Mode’ helps you write better React code by catching some of the issues as mentioned below:-
- Detecting unsafe lifecycle methods: React Strict Mode highlights the use of unsafe lifecycle methods such as componentWillMount() and componentWillUpdate(), which are prone to cause bugs and are deprecated in newer versions of React.
- Identifying side effects: React Strict Mode warns about components that have side effects outside of rendering, such as modifying global variables or directly manipulating the DOM.
- Highlighting prop-type issues: React Strict Mode helps catch potential issues with prop types, such as when a component is passed an incorrect data type for a prop.
- Catching errors and warnings: React Strict Mode enables additional checks that help catch errors and warnings that might otherwise go unnoticed during development.
- Encouraging best practices: The use of React Strict Mode encourages you to adopt best practices and follow recommended patterns, ultimately leading to cleaner and more maintainable code.
So, by highlighting the above issues and warnings about deprecated code practices, ‘React Strict Mode’ helps you identify and fix potential problems earlier in the development cycle enabling you to write better quality and more stable React code.
Let’s see an example of how to use ‘React Strict Mode’.
Example
Suppose we have a simple React component that renders a button and a counter:-
import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; return ( <div> <button onClick={handleClick}>Click me</button> <p>Count: {count}</p> </div> ); } export default Counter;
To use “React Strict Mode”, we can simply wrap the component in a <React.StrictMode> component:-
import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; return ( <React.StrictMode> <div> <button onClick={handleClick}>Click me</button> <p>Count: {count}</p> </div> </React.StrictMode> ); } export default Counter;
Now, suppose we want to use the count state variable in a useEffect hook to perform a side-effect when the component is mounted. We can modify the component as follows:-
import React, { useState, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; useEffect(() => { console.log(`Component mounted with count: ${count}`); }, [count]); return ( <React.StrictMode> <div> <button onClick={handleClick}>Click me</button> <p>Count: {count}</p> </div> </React.StrictMode> ); } export default Counter;
When we save and reload the component in the browser, we should see a warning in the console that says:-
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
This warning is produced because we are performing a state update during a render phase. To fix it, we can simply move the console.log statement to a separate function and call it in the useEffect hook:
import React, { useState, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); }; const logCount = () => { console.log(`Component mounted with count: ${count}`); }; useEffect(() => { logCount(); }, []); return ( <React.StrictMode> <div> <button onClick={handleClick}>Click me</button> <p>Count: {count}</p> </div> </React.StrictMode> ); } export default Counter;
Now, when we reload the component in the browser, the warning should disappear and the console.log statement should execute correctly when the component is mounted.
Is React Strict Mode Similar to Javascript ‘Use Strict’?
No, ‘React Strict Mode’ is not similar to Javascript’s ‘use strict’, however, both have been developed with a similar intention, which is, to provide a tool to help developers improve the quality and maintainability of their React code.
Here’s a comparison table between ‘React Strict Mode’ and ‘JavaScript use strict‘:-
React Strict Mode | JavaScript use strict | |
Usage | A feature provided by React | A directive added at the top of a JavaScript file |
Implementation | Added as a component around elements | Added as a directive at the top of a file or within a function |
Focus | Catching issues in React components | Enforcing stricter JavaScript rules |
Impact on the code | Identifies deprecated patterns and provides feedback without impacting production build | Disables some features that are prone to cause bugs or have unpredictable behavior and enforces stricter rules for variable declarations, function calls, and another syntax |
Does React Strict Mode Work Like a Debugger?
No, ‘React Strict Mode’ is not a debugger.
A Debugger is used to step through code and identify specific issues during runtime, whereas ‘React Strict Mode’ is used during development to prevent potential issues from occurring in the first place.
I personally use both ‘React Strict Mode’ and Debugger because they both complement each other and must be used in combination with other development tools, such as Browser Tools, and practices for optimal code quality, maintainability, and efficiency.
Below is a comparison table comparing both ‘React Strict Mode’ and Debugger to highlight the common differences between the both:-
React Strict Mode | Debugger | |
Purpose | Helps identify potential issues in React code during development | Pauses code execution to inspect the state of a program during development |
Functionality | Performs additional runtime checks and validations to improve code quality | Provides a powerful set of tools to debug and troubleshoot code during development |
Usage | Used to identify and prevent potential issues in code during development | Used to diagnose and fix issues in code during development |
Integration | Integrated into React applications through code | Integrated into developer tools in most modern web browsers |
Features | Additional runtime checks and warnings for potential issues in code | Ability to set breakpoints, step through code, and inspect variables during runtime |
Benefits | Helps catch potential bugs and improve code quality during development | Allows developers to debug and troubleshoot issues in code during development |
Limitations | Not a standalone tool for identifying and fixing issues in code | Can be time-consuming and may not always reveal the root cause of an issue |
Best Practice | Should be used in combination with other development tools and practices for optimal code quality | Should be used to troubleshoot and fix issues as they arise during development |
Recommended Use | Useful for proactive identification of potential issues in React code | Useful for reactive debugging and troubleshooting during development |
Is React Strict Mode an Exception Handling Technique?
No, React Strict Mode is not an exception-handling technique, however, both are used to identify and prevent potential issues in a React code.
Exception handling is a technique used by software programmers to catch errors and unexpected events that may occur during the execution of the program.
Here’s a small example of exception handling in ReactJS:-
Example
import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); const handleIncrement = () => { try { if (count >= 10) { throw new Error('Maximum limit reached!'); } setCount(count + 1); } catch (error) { console.error(error.message); } }; return ( <div> <p>Count: {count}</p> <button onClick={handleIncrement}>Increment</button> </div> ); } export default Example;
In the exception handling in React example above, we have a simple React component that uses the useState hook to manage a count state. The component also has a button that increments the count state when clicked. However, we have added a try-catch block in the handleIncrement function to handle exceptions.
In the try block, we check if the count state is already at the maximum value of 10. If it is, we throw a new error with the message ‘Maximum limit reached!’. If the count is less than 10, we simply update the count state using the setCount function.
In the catch block, we catch any error thrown in the try block and log the error message to the console using console.error.
This way, if an error is thrown in the try block, the catch block will handle it and log the error message to the console without crashing the application.
The same example above can also be written using both React Strict Mode and Try and Catch block. Here it is below:-
import React, { useState } from 'react'; function Example() { const [count, setCount] = useState(0); const handleIncrement = () => { try { if (count >= 10) { throw new Error('Maximum limit reached!'); } setCount(count + 1); } catch (error) { console.error(error.message); } }; return ( <React.StrictMode> <div> <p>Count: {count}</p> <button onClick={handleIncrement}>Increment</button> </div> </React.StrictMode> ); } export default Example;
In the above example, we have wrapped our component inside React.StrictMode component to enable strict mode. The try-and-catch blocks remain the same as in the previous example, but now any warnings or errors that are detected by the strict mode will be displayed in the console.
As we already know that React Strict Mode will detect any potential issue or bug in our code during development thus in this example, it helps us identify any issue related to the use of useState hook and ensure that our code is following the best practices.
What are the best features of React Strict Mode?
While working on developing a new feature ‘Async Rendering’ to be released in version 16 of React, the React development team learned a few lessons, such as legacy component lifecycles encouraged unsafe coding practices. These lifecycles were:-
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
Thus, React Strict Mode aka <React.StrictMode> component was written to detect and warn about unsafe lifecycle methods.
Gradually, more features such as warnings about deprecated APIs, etc were added for the benefit of the developer helping him/her to write a future-proof code and also ensuring code is compatible with the latest versions of ReactJS.
Below are the 6 best compelling features of React Strict Mode:-
Detecting Unsafe Lifecycle Methods
React components have several lifecycle methods, such as componentDidMount and componentWillUnmount, that are invoked during various stages of the component’s lifecycle.
Some of these lifecycle methods were deprecated or removed from React’s version 16.3 onwards due to their tendency to encourage unsafe coding practices.
‘React Strict Mode’ helps detect these unsafe lifecycle methods and warns you about the usage of these in your code.
By detecting and eliminating unsafe lifecycle methods, you can ensure your code is more robust and future-proof.
The most common unsafe lifecycle methods which can cause performance, reliability, and maintainability in React are:-
- componentWillMount() – This method is called just before a component mounts to the DOM. It is considered unsafe because it can cause issues with server rendering and can lead to inconsistencies between the server and client-side rendering.
- componentWillReceiveProps() – This method is called when a component receives new props. It is considered unsafe because it can lead to unnecessary re-rendering of components and can cause performance issues.
- componentWillUpdate() – This method is called just before a component updates. It is considered unsafe because it can cause issues with server rendering and can lead to inconsistencies between the server and client-side rendering.
- shouldComponentUpdate() – This method is called before a component updates, and it determines whether or not the component should update. It is considered unsafe because it can cause issues with performance, especially when used improperly.
- componentWillUnmount() – This method is called just before a component is removed from the DOM. It is considered unsafe because it can cause memory leaks and other issues if not handled properly.
Highlighting Deprecated APIs
React is constantly evolving, and some APIs that were previously recommended are now deprecated.
Thus if you use these deprecated APIs in your React code then they can lead your code toward potential issues and bugs which you would never want as a careful React developer.
‘React Strict Mode’ helps you identify and highlight these deprecated APIs in your code encouraging you to update your code to use the latest and recommended APIs.
Identifying Potential Side Effects
In React, a side effect is any action that occurs outside the component, such as making an API request or updating the browser’s location.
Side effects can lead to unexpected behavior and bugs in your code.
‘React Strict Mode’ helps you identify potential side effects in your components and warns you about them.
The example we read in the introduction section of this article identifies a potential side effect and issues us a warning to fix it.
Warning About Legacy String Ref API Usage
If you remember, in earlier versions of React, you used string refs to reference the DOM elements.
However, the string ref API has been deprecated in favor of the callback ref API, in React version 16, so using the string ref API can lead to unexpected behavior and bugs in your code.
‘React Strict Mode’ warns you about using the legacy string ref API and encourages you to update your React code to use the newer callback ref API as shown in a code example below:-
Example
This example shows a React component using a simple ref API with React.StrictMode component and giving us a warning that we are using a legacy API.
import React, { useRef } from 'react'; function MyComponent() { const inputRef = 'myInput'; const handleButtonClick = () => { console.log(this.refs[inputRef].value); }; return ( <React.StrictMode> <div> <input type="text" ref={inputRef} /> <button onClick={handleButtonClick}>Log input value</button> </div> </React.StrictMode> ); }
The warning we get is:-
Warning: A string ref, "myInput", has been used in MyComponent. This pattern is a legacy practice and is not recommended in modern React applications. Instead, use the callback ref API introduced with React 16 and higher. Learn more about using refs safely here: https://reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs
The updated component using callback ref API is:-
import React, { useRef } from 'react'; function MyComponent() { const inputRef = useRef(null); const handleButtonClick = () => { console.log(inputRef.current.value); }; return ( <React.StrictMode> <div> <input type="text" ref={inputRef} /> <button onClick={handleButtonClick}>Log input value</button> </div> </React.StrictMode> ); }
Warning about Legacy Context API Usage
‘React Strict Mode’ as of version 18 warns you about using Legacy Context API in your React code asking you to upgrade to a newer version of the Context API.
The new Context API is more powerful and easier to use, and also provides better performance and scalability.
React.StrictMode detects the use of Legacy Context API by checking for certain patterns in the code, such as accessing the context property of a component or passing an object as a context value.
Warning about deprecated findDOMNode usage
React.StrictMode warns about the deprecated use of findDOMNode() by checking for calls to this method in the code.
This is because findDOMNode() can cause performance issues and is generally discouraged in modern React applications.
The alternative approach to using findDOMNode() is to use the ref attribute to create a reference to a DOM element, and then manipulate the DOM element using the reference.
Let’s see an example code doing such as below:-
class MyComponent extends React.Component { constructor(props) { super(props); this.inputRef = React.createRef(); } handleButtonClick() { console.log(this.inputRef.current.value); } render() { return ( <React.StrictMode> <div> <input type="text" ref={this.inputRef} /> <button onClick={() => this.handleButtonClick()}>Log input value</button> </div> </React.StrictMode> ); } }
In the example above, we created a reference to the input element using the ref attribute and createRef(). We can then access the value of the input element using the current property of the ref object.
Using the ref attribute instead of findDOMNode() is a more modern and efficient way of manipulating the DOM in React, and is recommended by React.StrictMode.
Identifying issues Related to React v18’s Unmounting and Remounting Architecture
In React v18, a new strict mode behavior has been introduced for unmounting and remounting.
With this new behavior, every element is unmounted and remounted with the exact same state and effects as when it was initially mounted.
The process of mounting and remounting an element using old behavior is as follows:-
- The element is initially mounted.
- Side effects are generated.
- Strict mode now emulates the removal of these effects.
- When the component is mounted again, the same side effects are applied.
This old unmounting and remounting architecture can introduce some potential issues, such as unintended component re-rendering or unexpected side effects. ‘React Strict Mode’ helps catch these issues by running components in a stricter development mode.
Let’s see how we can use React Strict Mode with this new unmount and remount architecture:-
import React, { useState } from 'react'; function Counter() { const [count, setCount] = useState(0); return ( <React.StrictMode> <div> <h1>Count: {count}</h1> <button onClick={() => setCount(count + 1)}>Increment</button> </div> </React.StrictMode> ); } export default Counter;
Improving Development Experience and Promoting Best Practices
‘React Strict Mode’ helps improve the development experience by catching potential issues and bugs early on in the development process and by ensuring your code is more robust and future-proof.
Summary
As a React developer, you can use ‘React Strict Mode’ to catch potential issues early and write better code.
It detects unsafe lifecycle methods, warns about deprecated APIs, identifies potential side effects, and promotes best practices helping you to improve your development experience.
Strict Mode in React is not a debugging tool but it can prevent issues from being deployed to production by providing additional checks and warnings.
If you enjoyed this, be sure to check out our other React articles.
- 24+ React UI Component Libraries
- React vs Backbone.js: Which Is Best for Your Project?
- React WebSockets: Tutorial
- A Comprehensive Guide to Server-Side Rendering in React
- Svelte Vs React: Which Is Better
FAQ
What is React Strict Mode?
React Strict Mode is a tool in React that helps in identifying potential issues in an application. It does not render any visible UI but activates additional checks and warnings for its descendants. These checks are run only in development mode and do not affect the production build.
What is the use of Strict Mode in JavaScript?
JavaScript’s strict mode is a way to opt into a restricted variant of JavaScript, aiming to fix mistakes that affect JavaScript engines’ optimizations and to prohibit syntax likely to be defined in future ECMAScript versions. It enhances code security by preventing common errors, such as accidental global variable declarations, and makes the code more efficient by disabling features that slow down the JavaScript engine.