VOOZH about

URL: https://blog.logrocket.com/react-tracked-manage-state-prevent-excessive-re-rendering/

โ‡ฑ React Tracked: Manage state and prevent excessive re-rendering - LogRocket Blog


2021-09-23
1076
#react
Kasra Khosravi
67535
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

Over the last few years, state management in React has undergone a major evolution. With solutions like the built-in React Context API and React Redux, it has never been easier to keep a global state and track changes. However, one persisting challenge when implementing these tools is optimizing performance and preventing components from unnecessarily re-rendering.

๐Ÿ‘ Optimize Re rendering React Tracked

While in a smaller application, excessive re-rendering may be unnoticeable or have no negative impact, as your application grows, each re-render may cause delays or lags in your UI. In this tutorial, weโ€™ll use React Tracked, a library for state usage tracking, to optimize our applicationโ€™s performance by preventing unnecessary re-renders.

๐Ÿš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

Installing React Tracked

To get started, set up a new React project on your machine. Open the project in the terminal and add the following command to install the React Tracked library:

yarn add react-tracked scheduler 

Now, letโ€™s clean up our project by giving it the following structure:

๐Ÿ‘ React Tracked Project Structure

Setting up our application

Letโ€™s compare React Tracked with the vanilla React implementation of a shared state. Weโ€™ll create a simple global context that has two counter components, each using one value.

Add the following code in App.js:

import Counter1 from "./Counter1";
import Counter2 from "./Counter2";

import { SharedStateProvider } from "./store";

function App() {
 return (
 <>
 <SharedStateProvider>
 <div
 style={{
 display: "flex",
 flexDirection: "row",
 border: "1px solid black",
 justifyContent: "space-around",
 }}
 >
 <Counter1 />
 <Counter2 />
 </div>
 </SharedStateProvider>
 </>
 );
}

export default App;

To create the counter components, add the following code in each file:

Counter1

import React from "react";
import { useSharedState } from "./store";

export default function Counter1() {
 const [state, setState] = useSharedState();

 const increment = () => {
 setState((prev) => ({ ...prev, count1: prev.count1 + 1 }));
 };

 return (
 <div>
 {state.count1}
 {console.log("render counter 1")}

 <button onClick={increment}>Increment count1</button>

 </div>
 );
}

Counter2

import React from "react";
import { useSharedState } from "./store";

export default function Counter2() {
 const [state, setState] = useSharedState();

 const increment = () => {
 setState((prev) => ({ ...prev, count2: prev.count2 + 1 }));
 };

 return (
 <div>
 {state.count1}
 {console.log("render counter 2")}

 <button onClick={increment}>Increment count2</button>

 </div>
 );
}

store.js

Lastly, letโ€™s create our store.js file, which uses the global counter context and the useSharedState() Hook for the states in the counter component:

import React, { createContext, useState, useContext } from "react";

const initialState = {
 count1: 0,
 count2: 0,
};

const useValue = () => useState(initialState);

const MyContext = createContext(null);

export const useSharedState = () => {
 const value = useContext(MyContext);
 return value;
};

export const SharedStateProvider = ({ children }) => (
 <MyContext.Provider value={useValue()}>{children}</MyContext.Provider>
);

To run the project, add the following command:

yarn start

Now, weโ€™ll see the following output on the browser screen:

๐Ÿ‘ React Tracked Counter Increment Button

Open the browser console and hit each Increment button three times. Weโ€™ll receive the following output:

๐Ÿ‘ Increment Button Re-render Output

Each component re-rendered regardless of whether the state was updated. Ideally, the component should re-render only when the state is changed.

In our example, there should have been a total of six re-renders, three for both components, however, we wound up with 12, indicating that both components re-rendered on each click.

Rendering a large list

Now, letโ€™s try rendering a large list of elements. Add the code below to both Counter1 and Counter2 to generate a list of 10,000 random numbers in each component:

import React, { useEffect, useState } from "react";
import { useSharedState } from "./store";

export default function Counter1() {
 const [state, setState] = useSharedState();

 const [randomNumbers, setRandomNumbers] = useState([]);
 const increment = () => {
 setState((prev) => ({ ...prev, count1: prev.count1 + 1 }));
 };
 const generateHugeList = () => {
 let list = [];
 for (let i = 0; i < 10000; i++) {
 list.push(Math.floor(Math.random() * 10));
 }
 setRandomNumbers(list);
 };
 useEffect(() => {
 generateHugeList();
 }, []);
 return (
 <div>
 {state.count1}
 {console.log("render counter 1")}

 <button onClick={increment}>Increment count1</button>
 {randomNumbers.map((number) => {
 return <p>{number}</p>;
 })}
 </div>
 );
}

The counter components render the list on the browser, producing an output similar to the following:

๐Ÿ‘ Random Numbers Counter Components

With the introduction of these new elements, our application requires more time to load:

๐Ÿ‘ Application Load Time New Elements

On the first load, CPU usage jumps to 100 percent:

๐Ÿ‘ CPU Usage Graph First Load

React will paint all the elements to the browser DOM on the first render, so 100 percent CPU usage is typical. However, after clicking the Increment button on each counter component, the CPU usage remains at 100 percent, indicating that both counters are re-rendered constantly:

๐Ÿ‘ React Re-rendering CPU Usage Graph

Options for preventing re-renders

One popular method for preventing re-renders is using Selectors in React Redux, which are functions that subscribe to the Redux store and run whenever an action is dispatched. Selectors use === as a strict quality check, re-rendering the component whenever data is changed. While this process works well for variables, functions, which return a new reference each time the data is changed, are re-rendered constantly.

On the other hand, React Tracked wraps the context object and returns its own provider by using JavaScript proxies to track changes to the individual attribute of the state.



Proxies wrap a single object, intercepting or changing its fundamental operations. React Tracked implements proxies that examine the state inside of a component, re-rendering it only if the information changes. To see proxies in action, letโ€™s implement React Tracked in our application.

Rendering a list with React Tracked

First, we need to modify the store.js file that we created earlier by adding the following code:

import { useState } from "react";
import { createContainer } from "react-tracked";

const initialState = {
 count1: 0,
 count2: 0,
};

const useMyState = () => useState(initialState);

export const { Provider: SharedStateProvider, useTracked: useSharedState } =
 createContainer(useMyState);

In the code above, we import createContainer(), which returns a React Tracked provider. The useTracked Hook creates a proxy for our state.

Now, letโ€™s rebuild the project and compare the output from earlier to the output with React Tracked:

๐Ÿ‘ React Tracked CPU Usage Graph

As an example, when we select the Increment count1 button, on the first render, both Counter1 and Counter2 are rendered. However, on subsequent clicks, only Counter1 is re-rendered, reducing CPU usage overall and improving our appโ€™s performance.


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

Conclusion

In this tutorial, we explored the unwanted performance drawbacks that are caused by unnecessary re-rendering. While tools like React Redux and the React Context API make it easy to track changes in your applicationโ€™s state, they do not provide a straightforward solution to minimizing re-renders.

Using the React Tracked library, we built an application and minimized the number of times our counter components were re-rendered, decreasing the usage of our CPU and improving performance overall. I hope you enjoyed this tutorial!

Get set up with LogRocket's modern React error tracking in minutes:

  1. Visit https://logrocket.com/signup/ to get an app ID
  2. Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not server-side

    $ npm i --save logrocket 
    
    // Code:
    
    import LogRocket from 'logrocket'; 
    LogRocket.init('app/id');
     
    // Add to your HTML:
    
    <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
    <script>window.LogRocket && window.LogRocket.init('app/id');</script>
     
  3. (Optional) Install plugins for deeper integrations with your stack:
    • Redux middleware
    • NgRx middleware
    • Vuex plugin
Get started now
๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

How to build a virtual engineering team with Gemini CLI subagents

Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.

๐Ÿ‘ Image
Emmanuel John
Jun 18, 2026 โ‹… 10 min read

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

๐Ÿ‘ Image
Emmanuel John
Jun 17, 2026 โ‹… 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

๐Ÿ‘ Image
Chizaram Ken
Jun 16, 2026 โ‹… 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ€” no new framework required.

๐Ÿ‘ Image
Ikeh Akinyemi
Jun 12, 2026 โ‹… 6 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocketโ€™s Content Advisory Board. Youโ€™ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now