Skip to content

Instantly share code, notes, and snippets.

@gourav-singhal
Forked from mrousavy/MEMOIZE.md
Created June 29, 2022 07:55
Show Gist options
  • Select an option

  • Save gourav-singhal/d4d331d2320f7f9127f27227e7f2762f to your computer and use it in GitHub Desktop.

Select an option

Save gourav-singhal/d4d331d2320f7f9127f27227e7f2762f to your computer and use it in GitHub Desktop.

Revisions

  1. @mrousavy mrousavy revised this gist Apr 16, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -86,7 +86,7 @@ return <View style={style} />

    * Reanimated styles from `useAnimatedStyle`, as those have to be dynamic.

    > See [useStyle.ts](https://gist.github.com/mrousavy/bc3b748c56330bec09f128ecb4be0acb)
    > See [react-native-style-utilities](https://github.com/mrousavy/react-native-style-utilities) for the `useStyle` hook
    <br /><br /><br /><br /><br /><br />

  2. @mrousavy mrousavy revised this gist Apr 9, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -274,9 +274,11 @@ If your app feels slow, try the [react-native-performance](https://github.com/ob
    <a align="right" href="https://twitter.com/mrousavy">
    <img src="https://img.shields.io/twitter/follow/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    <br />
    <a align="right" href="https://github.com/mrousavy?tab=followers">
    <img src="https://img.shields.io/github/followers/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    <br />
    <a align="right" href='https://ko-fi.com/F1F8CLXG' target='_blank'>
    <img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
    </a>
  3. @mrousavy mrousavy revised this gist Apr 9, 2021. 1 changed file with 4 additions and 6 deletions.
    10 changes: 4 additions & 6 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -271,15 +271,13 @@ If your app feels slow, try the [react-native-performance](https://github.com/ob


    <div align="right">
    <a align="right" href='https://ko-fi.com/F1F8CLXG' target='_blank'>
    <img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
    <a align="right" href="https://twitter.com/mrousavy">
    <img src="https://img.shields.io/twitter/follow/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    <br/>
    <a align="right" href="https://github.com/mrousavy?tab=followers">
    <img src="https://img.shields.io/github/followers/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    <br/>
    <a align="right" href="https://twitter.com/mrousavy">
    <img src="https://img.shields.io/twitter/follow/mrousavy?label=Follow%20%40mrousavy&style=social" />
    <a align="right" href='https://ko-fi.com/F1F8CLXG' target='_blank'>
    <img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
    </a>
    </div>
  4. @mrousavy mrousavy revised this gist Apr 9, 2021. 1 changed file with 16 additions and 1 deletion.
    17 changes: 16 additions & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -267,4 +267,19 @@ If your app feels slow, try the [react-native-performance](https://github.com/ob

    <br /><br /><br /><br /><br /><br />
    <p align="center"><b>memoize!!</b></p>
    <br /><br /><br /><br /><br /><br />
    <br /><br /><br /><br /><br /><br />


    <div align="right">
    <a align="right" href='https://ko-fi.com/F1F8CLXG' target='_blank'>
    <img height='36' style='border:0px;height:36px;' src='https://az743702.vo.msecnd.net/cdn/kofi2.png?v=0' border='0' alt='Buy Me a Coffee at ko-fi.com' />
    </a>
    <br/>
    <a align="right" href="https://github.com/mrousavy?tab=followers">
    <img src="https://img.shields.io/github/followers/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    <br/>
    <a align="right" href="https://twitter.com/mrousavy">
    <img src="https://img.shields.io/twitter/follow/mrousavy?label=Follow%20%40mrousavy&style=social" />
    </a>
    </div>
  5. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -52,7 +52,8 @@ Reference comparisons simply compare the memory address of the variable, so only

    If you create objects in your render function, they will be re-created on every single render. This means when you create an object in the first render, it is not _reference-equal_ to the object in the second render. For this very reason, memoization exists.

    Use the `useMemo` hook to memoize arrays and objects which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) stay the same. Use the `useCallback` hook to memoize a function.
    * Use the `useMemo` hook to memoize arrays and objects which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) stay the same. Also use `useMemo` to cache heavy computations, such as array operations, filtering, etc.
    * Use the `useCallback` hook to memoize a function.

    In general, function components can be optimized more easily due to the concept of [hooks](https://reactjs.org/docs/hooks-overview.html). You can however apply similar techniques for class components, just be aware that this will result in a lot more code.

  6. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -18,7 +18,7 @@ It's important to memoize heavy computations as well as arrays and object creati

    A [Pure Component](https://reactjs.org/docs/react-api.html#reactpurecomponent) (or a `React.memo` component) does not re-render if it's props are _shallow equal_.

    Each variable you create in your render function will get re-allocated on each render. While this is not a problem for value types, this causes reference types to be different on every render. When you pass those variables down to pure components via props, they will still re-render even though the props are logically the same. Often those variables even go over the Bridge and make your app slow.
    Each variable you create in your render function will get re-allocated on each render. While this is not a problem for **value types**, this causes **reference types** to be different on every render. When you pass those variables down to **pure components** via props, they will still re-render even though the props are logically the same. Often those variables even go over the Bridge and make your app slow.

    ## Reference equality

  7. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 11 additions and 5 deletions.
    16 changes: 11 additions & 5 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -12,17 +12,21 @@ inputs occur again. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs

    # Memoization in React

    It's important to memoize heavy computations as well as arrays and object creations so that they don't get re-created on every render. A re-render occurs when state changes, redux dispatches some action, or when the user types into a text input (re-render for every single key press). You don't want to run a lot of operations in those renders for very obvious reasons. So no heavy filtering, no list operations, etc.
    It's important to memoize heavy computations as well as arrays and object creations so that they don't get re-created on every render. A re-render occurs when state changes, redux dispatches some action, or when the user types into a text input (re-render for every single key press). You don't want to run a lot of operations in those renders for very obvious reasons - so no heavy filtering, no list operations, etc.

    Each variable you create in your render function will get re-allocated each render. While this is not a problem for types that can be _compared by value_ (numbers, booleans, strings), this causes objects which have to be _compared by reference_ (objects, arrays, functions) to be different on every render. When those objects don't maintain reference equality, React thinks that you passed a different variable to subcomponents, and will trigger re-renders for those too. Often those variables even go over the Bridge and make your app slow.
    ## Pure Components

    A [Pure Component](https://reactjs.org/docs/react-api.html#reactpurecomponent) (or a `React.memo` component) does not re-render if it's props are _shallow equal_.

    Each variable you create in your render function will get re-allocated on each render. While this is not a problem for value types, this causes reference types to be different on every render. When you pass those variables down to pure components via props, they will still re-render even though the props are logically the same. Often those variables even go over the Bridge and make your app slow.

    ## Reference equality

    When a React component re-renders, it compares the previous props to the current props and checks if they are _shallow-equal_.
    When a pure component re-renders, it compares the previous props to the current props and checks if they are _shallow-equal_.

    ### Value types

    Numbers, strings and booleans are **value types**, which means they can be _compared by value_:
    **Numbers**, **strings** and **booleans** are **value types**, which means they can be _compared by value_:

    ```js
    const i1 = 7;
    @@ -32,7 +36,7 @@ const equal = i1 === i2; // true

    ### Reference types

    Objects, arrays and functions are **reference types**, which means they cannot be compared by their logical value, but have to be _compared by reference_:
    **Objects**, **arrays** and **functions** are **reference types**, which means they cannot be compared by their logical value, but have to be _compared by reference_:

    ```js
    const o1 = { x: 7 };
    @@ -56,6 +60,8 @@ In general, function components can be optimized more easily due to the concept

    While animations and performance intensive tasks are scheduled on native threads, your entire business logic runs on a single JavaScript thread, so make sure you're doing as little work as possible there. Doing too much work on the JavaScript thread can be compared to a high ping in a video game - you can still look around smoothly, but you can't really play the game because every interaction takes too long.

    Native components (`<View>`, `<Text>`, `<Image>`, `<Blurhash>`, ...) have to pass props to native via the bridge. They can be memoized, so React compares the props for _shallow-equality_ and only passes them over the bridge if they are different than the props from the last render. If you don't memoize correctly, you might up passing props over the bridge for every single render, causing the bridge to be very occupied. See the [Styles](#styles) example - styles will get sent over the bridge on every re-render!

    Here are a few examples to help you avoid doing too much work on your JavaScript thread:

    # Examples
  8. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 13 additions and 7 deletions.
    20 changes: 13 additions & 7 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -18,29 +18,35 @@ Each variable you create in your render function will get re-allocated each rend

    ## Reference equality

    When a React component re-renders, it compares the previous props to the current props and checks if they are _shallow-equal_.
    When a React component re-renders, it compares the previous props to the current props and checks if they are _shallow-equal_.

    Assuming you create two variables, both of the same type and same value, they are not guaranteed to be equal. Only "value types" can be shallow-compared successfully, while "reference types" have to be _reference equal_. Here's a code example to demonstrate this:
    ### Value types

    Numbers, strings and booleans are **value types**, which means they can be _compared by value_:

    ```js
    const i1 = 7;
    const i2 = 7;
    const equal = i1 === i2;
    const equal = i1 === i2; // true
    ```

    In this case, numbers are "value types" and can be compared by value. They are equal, the variable `equal` is therefore `true`. **This applies to numbers, booleans and strings**.
    ### Reference types

    Objects, arrays and functions are **reference types**, which means they cannot be compared by their logical value, but have to be _compared by reference_:

    ```js
    const o1 = { x: 7 };
    const o2 = { x: 7 };
    const equal = o1 === o2;
    const equal = o1 === o2; // false
    ```

    In this case, two objects get created. Since objects can get quite complex and go deeper than a single value, they are only compared for _reference equality_. In this case, we have two objects, and `o1` is a reference to the first object, while `o2` is a reference to the second object. This means, they are not _reference-equal_, `equals` is therefore `false`. **This applies to objects, arrays and functions**.
    Reference comparisons simply compare the memory address of the variable, so only `o1 === o1` would be `true` in the above code example.

    > There are libraries like [deep-equal](https://github.com/inspect-js/node-deep-equal) to compare objects by actual equality, but that's not _shallow equality_ anymore.
    ### React

    In React your component's `render()` function (or simply a function component's function) is executed on each render. If you create objects in this function, they will be re-created on every single render. This means when you create an object in the first render, it is not reference-equal to the second render. For this very reason, memoization exists.
    If you create objects in your render function, they will be re-created on every single render. This means when you create an object in the first render, it is not _reference-equal_ to the object in the second render. For this very reason, memoization exists.

    Use the `useMemo` hook to memoize arrays and objects which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) stay the same. Use the `useCallback` hook to memoize a function.

  9. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -14,7 +14,7 @@ inputs occur again. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbs

    It's important to memoize heavy computations as well as arrays and object creations so that they don't get re-created on every render. A re-render occurs when state changes, redux dispatches some action, or when the user types into a text input (re-render for every single key press). You don't want to run a lot of operations in those renders for very obvious reasons. So no heavy filtering, no list operations, etc.

    If variables get re-created each render, they won't maintain reference equality. When they don't maintain reference equality, React thinks that you passed a different variable to subcomponents, and will trigger re-renders for those too. Often those variables even go over the Bridge and make your app slow.
    Each variable you create in your render function will get re-allocated each render. While this is not a problem for types that can be _compared by value_ (numbers, booleans, strings), this causes objects which have to be _compared by reference_ (objects, arrays, functions) to be different on every render. When those objects don't maintain reference equality, React thinks that you passed a different variable to subcomponents, and will trigger re-renders for those too. Often those variables even go over the Bridge and make your app slow.

    ## Reference equality

  10. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -246,7 +246,7 @@ If your component renders the same result given the same props, you can wrap it

    ## react-native-performance

    If your app feels slow, try the [react-native-performance](https://github.com/oblador/react-native-performance) library and it's flipper plugin to profile your app's performance.
    If your app feels slow, try the [react-native-performance](https://github.com/oblador/react-native-performance) library and it's flipper plugin to profile your app's performance in various aspects such as _time to interactive_, _component render time_, _script execution_ and more.

    <br /><br /><br /><br /><br /><br />

  11. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 6 additions and 0 deletions.
    6 changes: 6 additions & 0 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -244,6 +244,12 @@ If your component renders the same result given the same props, you can wrap it

    <br /><br /><br /><br /><br /><br />

    ## react-native-performance

    If your app feels slow, try the [react-native-performance](https://github.com/oblador/react-native-performance) library and it's flipper plugin to profile your app's performance.

    <br /><br /><br /><br /><br /><br />

    # Conclusion

    <br /><br /><br /><br /><br /><br />
  12. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 26 additions and 1 deletion.
    27 changes: 26 additions & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -153,7 +153,9 @@ function MyComponent(props) {

    ```jsx
    function MyComponent(props) {
    const scrollViewProps = useMemo(() => ({ horizontal: props.isHorizontal }), [props.isHorizontal]);
    const scrollViewProps = useMemo(() => ({
    horizontal: props.isHorizontal
    }), [props.isHorizontal]);
    return <RecyclerListView scrollViewProps={scrollViewProps} />;
    }
    ```
    @@ -216,6 +218,29 @@ function ComponentImWorkingOn() {

    You can also use the [why-did-you-render](https://github.com/welldone-software/why-did-you-render) library to find out _why_ a component has re-rendered (prop changes, state changes, ...) and possibly catch mistakes early on.

    <br /><br /><br /><br /><br /><br />

    ## `React.memo`

    ### Bad

    ```jsx
    export const MyComponent = (props) => {
    return ...
    }
    ```

    ### Good

    ```jsx
    const MyComponentImpl = (props) => {
    return ...
    }

    export const MyComponent = React.memo(MyComponentImpl);
    ```

    If your component renders the same result given the same props, you can wrap it in a call to `React.memo(...)` for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result. See [the official docs for `React.memo`](https://reactjs.org/docs/react-api.html#reactmemo), and [use `React.memo(...)` wisely](https://dmitripavlutin.com/use-react-memo-wisely/).

    <br /><br /><br /><br /><br /><br />

  13. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 8 additions and 4 deletions.
    12 changes: 8 additions & 4 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -144,14 +144,18 @@ function MyComponent(props) {
    ### Bad

    ```jsx
    return <RecyclerListView scrollViewProps={{ horizontal: true }} />;
    function MyComponent(props) {
    return <RecyclerListView scrollViewProps={{ horizontal: props.isHorizontal }} />;
    }
    ```

    ### Good

    ```jsx
    const scrollViewProps = useMemo(() => ({ horizontal: true }), []);
    return <RecyclerListView scrollViewProps={scrollViewProps} />;
    function MyComponent(props) {
    const scrollViewProps = useMemo(() => ({ horizontal: props.isHorizontal }), [props.isHorizontal]);
    return <RecyclerListView scrollViewProps={scrollViewProps} />;
    }
    ```

    <br /><br /><br /><br /><br /><br />
    @@ -176,7 +180,7 @@ function MyComponent() {
    }
    ```

    This applies to objects as well as functions which don't depend on the component's state or props. Always use this, since it's even more efficient than `useMemo` and `useCallback`.
    This applies to objects as well as functions which don't depend on the component's state or props. Always use this if you can, since it's even more efficient than `useMemo` and `useCallback`.

    <br /><br /><br /><br /><br /><br />

  14. @mrousavy mrousavy revised this gist Mar 30, 2021. 1 changed file with 7 additions and 3 deletions.
    10 changes: 7 additions & 3 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -119,18 +119,22 @@ Make sure to also think about other calls in the renderer, e.g. `useSelector`, `

    <br /><br /><br /><br /><br /><br />

    ## Dumb Functions
    ## Forward-propagating Functions

    ### Bad

    ```jsx
    return <PressableOpacity onPress={() => logoutUser()} />
    function MyComponent(props) {
    return <PressableOpacity onPress={() => props.logoutUser()} />
    }
    ```

    ### Good

    ```jsx
    return <PressableOpacity onPress={logoutUser} />
    function MyComponent(props) {
    return <PressableOpacity onPress={props.logoutUser} />
    }
    ```

    <br /><br /><br /><br /><br /><br />
  15. @mrousavy mrousavy revised this gist Mar 26, 2021. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -196,7 +196,7 @@ const [me, setMe] = useState(() => users.find((u) => u.id === myUserId));

    ## Count re-renders

    When writing new components I always put a log statement in my render function to passively watch how often my component re-renders. In general, components should re-render as little as possible, and if I see a lot of logs appearing in my console I know I did something wrong. It's a good practice to put this function in your component while you're working on it, and remove it once done.
    When writing new components I always put a log statement in my render function to passively watch how often my component re-renders while I'm working on it. In general, components should re-render as little as possible, and if I see a lot of logs appearing in my console I know I did something wrong. It's a good practice to put this function in your component once you start working on it, and remove it once done.

    ```jsx
    function ComponentImWorkingOn() {
  16. @mrousavy mrousavy revised this gist Mar 26, 2021. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -48,9 +48,9 @@ In general, function components can be optimized more easily due to the concept

    ### React Native

    While animations and performance intensive tasks are scheduled on native threads, your entire business logic runs on a single JavaScript thread, so make sure you're doing as little work as possible there. Overloading the JavaScript thread can be compared to a high ping in a video game - you can still look around smoothly, but you can't really play the game because every interaction takes too long.
    While animations and performance intensive tasks are scheduled on native threads, your entire business logic runs on a single JavaScript thread, so make sure you're doing as little work as possible there. Doing too much work on the JavaScript thread can be compared to a high ping in a video game - you can still look around smoothly, but you can't really play the game because every interaction takes too long.

    Here are a few examples to help you avoid overloading your JavaScript thread:
    Here are a few examples to help you avoid doing too much work on your JavaScript thread:

    # Examples

  17. @mrousavy mrousavy revised this gist Mar 26, 2021. 1 changed file with 3 additions and 1 deletion.
    4 changes: 3 additions & 1 deletion MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -40,7 +40,9 @@ In this case, two objects get created. Since objects can get quite complex and g

    ### React

    In React your component's `render()` function (or simply a function component's function) is executed on each render. If you create objects in this function, they will be re-created on every single render. This means when you create an object in the first render, it is not reference-equal to the second render. For this very reason, memoization exists. Use the `useMemo` hook to memoize arrays and objects, which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) don't change. Use the `useCallback` hook to memoize a function.
    In React your component's `render()` function (or simply a function component's function) is executed on each render. If you create objects in this function, they will be re-created on every single render. This means when you create an object in the first render, it is not reference-equal to the second render. For this very reason, memoization exists.

    Use the `useMemo` hook to memoize arrays and objects which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) stay the same. Use the `useCallback` hook to memoize a function.

    In general, function components can be optimized more easily due to the concept of [hooks](https://reactjs.org/docs/hooks-overview.html). You can however apply similar techniques for class components, just be aware that this will result in a lot more code.

  18. @mrousavy mrousavy revised this gist Mar 26, 2021. 1 changed file with 2 additions and 0 deletions.
    2 changes: 2 additions & 0 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -71,6 +71,8 @@ return <View style={style} />

    * Reanimated styles from `useAnimatedStyle`, as those have to be dynamic.

    > See [useStyle.ts](https://gist.github.com/mrousavy/bc3b748c56330bec09f128ecb4be0acb)
    <br /><br /><br /><br /><br /><br />

    ## Arrays
  19. @mrousavy mrousavy created this gist Mar 26, 2021.
    214 changes: 214 additions & 0 deletions MEMOIZE.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,214 @@
    <div align="center">
    <blockquote>
    In computing, memoization or memoisation <br/>
    is an optimization technique used primarily <br/>
    to speed up computer programs by storing <br/>
    the results of expensive function calls and &nbsp;<br/>
    returning the cached result when the same <br/>
    inputs occur again. &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; — <a href="https://en.wikipedia.org/wiki/Memoization"><i>wikipedia</i></a>
    </blockquote>
    </div>

    # Memoization in React

    It's important to memoize heavy computations as well as arrays and object creations so that they don't get re-created on every render. A re-render occurs when state changes, redux dispatches some action, or when the user types into a text input (re-render for every single key press). You don't want to run a lot of operations in those renders for very obvious reasons. So no heavy filtering, no list operations, etc.

    If variables get re-created each render, they won't maintain reference equality. When they don't maintain reference equality, React thinks that you passed a different variable to subcomponents, and will trigger re-renders for those too. Often those variables even go over the Bridge and make your app slow.

    ## Reference equality

    When a React component re-renders, it compares the previous props to the current props and checks if they are _shallow-equal_.

    Assuming you create two variables, both of the same type and same value, they are not guaranteed to be equal. Only "value types" can be shallow-compared successfully, while "reference types" have to be _reference equal_. Here's a code example to demonstrate this:

    ```js
    const i1 = 7;
    const i2 = 7;
    const equal = i1 === i2;
    ```

    In this case, numbers are "value types" and can be compared by value. They are equal, the variable `equal` is therefore `true`. **This applies to numbers, booleans and strings**.

    ```js
    const o1 = { x: 7 };
    const o2 = { x: 7 };
    const equal = o1 === o2;
    ```

    In this case, two objects get created. Since objects can get quite complex and go deeper than a single value, they are only compared for _reference equality_. In this case, we have two objects, and `o1` is a reference to the first object, while `o2` is a reference to the second object. This means, they are not _reference-equal_, `equals` is therefore `false`. **This applies to objects, arrays and functions**.

    ### React

    In React your component's `render()` function (or simply a function component's function) is executed on each render. If you create objects in this function, they will be re-created on every single render. This means when you create an object in the first render, it is not reference-equal to the second render. For this very reason, memoization exists. Use the `useMemo` hook to memoize arrays and objects, which will keep their reference equality (and won't get re-created on each render) as long as the dependencies (second argument) don't change. Use the `useCallback` hook to memoize a function.

    In general, function components can be optimized more easily due to the concept of [hooks](https://reactjs.org/docs/hooks-overview.html). You can however apply similar techniques for class components, just be aware that this will result in a lot more code.

    ### React Native

    While animations and performance intensive tasks are scheduled on native threads, your entire business logic runs on a single JavaScript thread, so make sure you're doing as little work as possible there. Overloading the JavaScript thread can be compared to a high ping in a video game - you can still look around smoothly, but you can't really play the game because every interaction takes too long.

    Here are a few examples to help you avoid overloading your JavaScript thread:

    # Examples

    ## Styles

    ### Bad

    ```jsx
    return <View style={[styles.container, { backgroundColor: 'red' }]} />
    ```

    ### Good

    ```jsx
    const style = useStyle(() => [styles.container, { backgroundColor: 'red' }], []);
    return <View style={style} />
    ```

    ### Exceptions

    * Reanimated styles from `useAnimatedStyle`, as those have to be dynamic.

    <br /><br /><br /><br /><br /><br />

    ## Arrays

    Using `filter`, `map` or other array operations in renderers will run the entire operation again for every render.

    ### Bad

    ```jsx
    return <Text>{users.filter((u) => u.status === "online").length} users online</Text>
    ```

    ### Good

    ```jsx
    const onlineCount = useMemo(() => users.filter((u) => u.status === "online").length, [users]);
    return <Text>{onlineCount} users online</Text>
    ```

    You can also apply this to render multiple React views with `.map`. Those can be memoized with `useMemo` too.

    <br /><br /><br /><br /><br /><br />

    ## Functions

    ### Bad

    ```jsx
    return <View onLayout={(layout) => console.log(layout)} />
    ```

    ### Good

    ```jsx
    const onLayout = useCallback((layout) => {
    console.log(layout);
    }, []);
    return <View onLayout={onLayout} />
    ```

    Make sure to also think about other calls in the renderer, e.g. `useSelector`, `useComponentDidAppear` - wrap the callback there too!

    <br /><br /><br /><br /><br /><br />

    ## Dumb Functions

    ### Bad

    ```jsx
    return <PressableOpacity onPress={() => logoutUser()} />
    ```

    ### Good

    ```jsx
    return <PressableOpacity onPress={logoutUser} />
    ```

    <br /><br /><br /><br /><br /><br />

    ## Objects

    ### Bad

    ```jsx
    return <RecyclerListView scrollViewProps={{ horizontal: true }} />;
    ```

    ### Good

    ```jsx
    const scrollViewProps = useMemo(() => ({ horizontal: true }), []);
    return <RecyclerListView scrollViewProps={scrollViewProps} />;
    ```

    <br /><br /><br /><br /><br /><br />

    ## Lift out of render

    ### Bad

    ```jsx
    function MyComponent() {
    return <RecyclerListView scrollViewProps={{ horizontal: true }} />;
    }
    ```

    ### Good

    ```jsx
    const SCROLL_VIEW_PROPS = { horizontal: true }

    function MyComponent() {
    return <RecyclerListView scrollViewProps={SCROLL_VIEW_PROPS} />;
    }
    ```

    This applies to objects as well as functions which don't depend on the component's state or props. Always use this, since it's even more efficient than `useMemo` and `useCallback`.

    <br /><br /><br /><br /><br /><br />

    ## Initial States

    ### Bad

    ```jsx
    const [me, setMe] = useState(users.find((u) => u.id === myUserId));
    ```

    ### Good

    ```jsx
    const [me, setMe] = useState(() => users.find((u) => u.id === myUserId));
    ```

    [The `useState` hook accepts an initializer function](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state). While the first example ("Bad") runs the `.find` on every render, the second example only runs the passed function once to initialize the state.

    <br /><br /><br /><br /><br /><br />

    ## Count re-renders

    When writing new components I always put a log statement in my render function to passively watch how often my component re-renders. In general, components should re-render as little as possible, and if I see a lot of logs appearing in my console I know I did something wrong. It's a good practice to put this function in your component while you're working on it, and remove it once done.

    ```jsx
    function ComponentImWorkingOn() {
    // code
    console.log('re-rendering ComponentImWorkingOn!');
    return <View />;
    }
    ```

    You can also use the [why-did-you-render](https://github.com/welldone-software/why-did-you-render) library to find out _why_ a component has re-rendered (prop changes, state changes, ...) and possibly catch mistakes early on.


    <br /><br /><br /><br /><br /><br />

    # Conclusion

    <br /><br /><br /><br /><br /><br />
    <p align="center"><b>memoize!!</b></p>
    <br /><br /><br /><br /><br /><br />