# Performance Performance optimization in React Native applications is a complex and multifaceted challenge. It encompasses various aspects such as rendering efficiency, memory management, network operations, and native module interactions. Poor performance can manifest in different ways - from sluggish UI responses and excessive battery drain to memory leaks and app crashes. This guide aims to help you navigate this complex landscape by providing best practices, common pitfalls to avoid, and the right tools to measure and improve performance. Some topics that we'll cover include: - [Re-renders and component optimization](#re-renders-and-component-optimization) - [Tool(s) for identifying re-renders](#tools-for-identifying-re-renders) - [Automatically optimizing React](#automatically-optimizing-react) By understanding these areas and applying the recommended practices, you can create a more efficient and responsive application that provides a better user experience. ## Re-renders and component optimization > **Note on Over-Optimization**: While memoization is powerful, it's important to use it in moderation. Not every function or computed value needs to be memoized. > > Consider memoization when: > > - The computation is expensive (e.g., complex calculations, large array transformations) > - The value is used in dependency arrays of other hooks > > No need to optimize when: > > - The calculation is cheap > - You're just returning a primitive or constant > - It's not causing unnecessary re-renders or performance issues > > Avoid premature optimization. Start without memoization and add it only when you observe performance issues. Re-renders are a common source of performance issues in React Native applications. While some re-renders are necessary for updating the UI, unnecessary re-renders can significantly impact performance. Here are some areas that we've seen that can cause performance issues: ### Components Components that aren't memoized can re-render even when their props haven't changed. Best practices: - **React.memo**: Use for functional components to prevent unnecessary re-renders Example of component memoization: ```javascript // Bad - re-renders on every parent update const MyComponent = (props) => { /* ... */ }; // Good - only re-renders when props change const MyComponent = React.memo((props) => { /* ... */ }); ``` ### Selectors Selectors, especially in Redux or other state management solutions, can cause unnecessary re-renders if not properly optimized. Best practices: - **Memoize selectors**: Selectors that create new object references on each call can trigger re-renders even when the underlying data hasn't changed. Use memoized selectors such as [createSelector](https://reselect.js.org/api/createSelector) from [reselect](https://github.com/reduxjs/reselect) to prevent unnecessary re-renders. - **Selector Composition**: Complex selector chains can lead to multiple re-renders. Keep selectors focused and simple. Example of selector optimization: ```javascript // Bad - creates new array every time const getActiveItems = (state) => { return state.items.filter((item) => item.isActive); }; const getAllItems = (state) => { return state.items; }; // Good - memoized selector and only recomputes when state.items changes const getActiveItems = createSelector(getAllItems, (items) => items.filter((item) => item.isActive), ); ``` ### Hooks and Functions Hooks and functions that aren't properly memoized can cause unnecessary re-renders. Best practices: - [**useMemo**](https://react.dev/reference/react/useMemo): Computed values should be memoized to prevent recalculation on every render, especially for computed values that are expensive to compute. - [**useCallback**](https://react.dev/reference/react/useCallback): Complex functions created inside components should be wrapped in `useCallback` to maintain referential equality. - [**useEffect**](https://react.dev/reference/react/useEffect): Apply correct dependencies to `useEffect` to prevent unnecessary triggers and re-renders. Example of memoizing a computed value using `useMemo`: ```javascript // Bad - new array created every render const items = data.map((item) => ({ ...item, processed: processItem(item), })); // Good - memoized array transformation that changes only when data changes const items = useMemo( () => data.map((item) => ({ ...item, processed: processItem(item), })), [data], ); ``` Example of memoizing a function using `useCallback`: ```javascript // Bad - new function created every render const onPress = () => { /* ... */ }; // Assume Button is memoized - still re-renders on parent update because onPress is a new function reference on each render return