Skip to content

FlashList v2 #1617

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 93 commits into from
May 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
94c432e
Implement new RecyclerView prototype with enhanced features and React…
naqvitalha Apr 11, 2025
3fa91ad
Skip core swapping in tests
naqvitalha Apr 11, 2025
2108050
Add header offset to initial scroll
naqvitalha Apr 12, 2025
e095dc7
Add index to CellRendererComponent
naqvitalha Apr 14, 2025
7721d58
Remove completed TODO comments
naqvitalha Apr 14, 2025
efca6ae
Fix memoization in samples
naqvitalha Apr 14, 2025
c701e10
temporarily ignore fixture ts errors
naqvitalha Apr 15, 2025
ac6b19a
Update yarn.lock
naqvitalha Apr 15, 2025
6715280
remove random in samples
naqvitalha Apr 16, 2025
7ea6cff
build fix
naqvitalha Apr 16, 2025
7b6ff4c
Fix and add new e2e tests
naqvitalha Apr 16, 2025
c6fd8b7
pod update
naqvitalha Apr 16, 2025
f85ab84
Unit testing most of the code
naqvitalha Apr 17, 2025
fd46e0a
Fix lint errors
naqvitalha Apr 17, 2025
9cd6116
Fix sticky overflow
naqvitalha Apr 17, 2025
73cb3bd
Add docs 1.x and further edits to current docs
naqvitalha Apr 17, 2025
8e7eb3f
Fix chat flickers
naqvitalha Apr 17, 2025
fc413a7
Added TODO
naqvitalha Apr 17, 2025
8170e74
Improve scrollToIndex alogrithm
naqvitalha Apr 18, 2025
c12c0a1
version bump
naqvitalha Apr 18, 2025
00bb718
Optimize scrollTo for non animated situations
naqvitalha Apr 19, 2025
62609f4
v2.0.0-alpha.5
naqvitalha Apr 19, 2025
34f9194
Fix RTL horizontal lists
naqvitalha Apr 20, 2025
b0c4075
Add known issue for horizontal RTL
naqvitalha Apr 21, 2025
f270a96
v2.0.0-alpha.6
naqvitalha Apr 21, 2025
2671f0d
Fix unwanted mounts on data addition to top
naqvitalha Apr 22, 2025
7843219
Add note about horizontal lists
naqvitalha Apr 22, 2025
ba72bb8
Update usage guide
naqvitalha Apr 22, 2025
68eb378
Fix missing custom refresh control
naqvitalha Apr 22, 2025
184035f
v2.0.0-alpha.7
naqvitalha Apr 22, 2025
acec63e
Fix memo in docs
naqvitalha Apr 22, 2025
0ea23e5
Reduce draw distance in chat sample
naqvitalha Apr 22, 2025
cc7d868
change load time log
naqvitalha Apr 22, 2025
24ff2e8
Add new useMappingHelper hook for solving .map
naqvitalha Apr 23, 2025
8d595e0
Fix duplicate onStartReached calls
naqvitalha Apr 23, 2025
707ff7d
v2.0.0-alpha.8
naqvitalha Apr 23, 2025
bde35c1
Fix flicker when switching to masonry from grid
naqvitalha Apr 24, 2025
357e2df
Fix rendering on web and add a sample
naqvitalha Apr 24, 2025
034fe0c
Add more improvements for web
naqvitalha Apr 24, 2025
0d84563
Fix e2e test
naqvitalha Apr 24, 2025
674472c
v2.0.0-alpha.9
naqvitalha Apr 24, 2025
171c57e
Add delay in e2e
naqvitalha Apr 24, 2025
c1ffbbd
bump flash-list in web fixture
naqvitalha Apr 24, 2025
6bd25f0
Improve scrollTo accuracy even more
naqvitalha Apr 25, 2025
7c08bd7
Improve velocity tracking which was missing on web and iOS
naqvitalha Apr 27, 2025
bf5d0fb
Fix bugs introduced by buffer improvements
naqvitalha Apr 28, 2025
313c9ea
Improve buffer with render time
naqvitalha Apr 28, 2025
2d1f4a6
Add wait to e2e
naqvitalha Apr 28, 2025
eccec92
Fix e2e flakiness
naqvitalha Apr 28, 2025
5ece4d5
v2.0.0-alpha.10
naqvitalha Apr 28, 2025
ad97535
Add an auto scroll script
naqvitalha Apr 29, 2025
757d023
Fix sticky crash
naqvitalha Apr 30, 2025
dc10b29
Improve twitter sample
naqvitalha Apr 30, 2025
ec321e9
Upgrade fixture to RN 0.79.1
naqvitalha May 1, 2025
03f89c3
Update readme
naqvitalha May 4, 2025
49153e6
Fix lint errors and cleanup
naqvitalha May 7, 2025
d005c12
Code cleanup and add few more methods to FlashList's handler
naqvitalha May 7, 2025
d3277c6
Fix lint errors
naqvitalha May 7, 2025
ff960a0
Add measureLayout mocks
naqvitalha May 8, 2025
f9952cb
Update reanimated doc a bit
naqvitalha May 8, 2025
0ef85e5
bug fixes
naqvitalha May 8, 2025
8e9adb1
Add/Fix tests
naqvitalha May 9, 2025
60eb54a
Fix infinite render loop in Grid Layout
naqvitalha May 11, 2025
ce0947b
Improve sticky header compute
naqvitalha May 11, 2025
02ea042
Link to v1 docs
naqvitalha May 12, 2025
ae023af
Refactor recycling manager to be faster and more efficient
naqvitalha May 14, 2025
4d15495
Reconfigure benchmarks
naqvitalha May 14, 2025
a3fa711
Export RecyclerView as AnimatedFlashList
naqvitalha May 14, 2025
0811232
Change displayName of RecyclerView
naqvitalha May 14, 2025
b0dd7e0
export recyclerview as default FlashList for tests
naqvitalha May 14, 2025
fe1e6d4
v2.0.0-alpha.11
naqvitalha May 14, 2025
dcde7e5
Improve sticky headers animated setup
naqvitalha May 16, 2025
8f5c854
Fix intermitttent animation skips in sticky headers
naqvitalha May 16, 2025
309b718
Sample improvements
naqvitalha May 16, 2025
57ae4e6
Revert Animated.subtract as it breaks native driver
naqvitalha May 17, 2025
3622c8d
exp with mvcp in horizontal
naqvitalha May 21, 2025
f23455f
Implement clearLayoutCacheOnUpdate API from v1
naqvitalha May 21, 2025
b29ce0c
v2.0.0-alpha.12
naqvitalha May 21, 2025
57992c2
Enable strict mode in few samples
naqvitalha May 21, 2025
7a42168
Workaround for cases where useLayoutEffect fails to block paint
naqvitalha May 23, 2025
9fdd45e
Fix missing itemType in average compute
naqvitalha May 23, 2025
d52ac4d
Improve reconciliation (#1672)
naqvitalha May 23, 2025
66ff4c3
Improve render stack update
naqvitalha May 23, 2025
49e82bf
Add comment
naqvitalha May 23, 2025
ad52854
v2.0.0-alpha.13
naqvitalha May 23, 2025
f419192
Remove completed TODOs
naqvitalha May 23, 2025
1bb653a
Prevent getItemType calls for negative indices
naqvitalha May 26, 2025
df67809
2.0.0-alpha.14
naqvitalha May 26, 2025
4063129
Fix documentation build
naqvitalha May 26, 2025
5385b8b
Improve docs
naqvitalha May 26, 2025
9e332e9
Doc improvements
naqvitalha May 26, 2025
730b400
Fix any in ViewToken
naqvitalha May 26, 2025
af430af
2.0.0-rc.1
naqvitalha May 26, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = {
"@shopify/jsx-no-complex-expressions": "off",
"@shopify/react-prefer-private-members": "off",
"eslint-comments/disable-enable-pair": "off",
"@shopify/strict-component-boundaries": "off",
"import/no-cycle": "off",
"import/no-named-as-default": "off",
"max-params": "off",
Expand All @@ -40,6 +41,12 @@ module.exports = {
"@typescript-eslint/member-ordering": "off",
"@typescript-eslint/consistent-indexed-object-style": "off",
"jsx-a11y/no-autofocus": "off",
"line-comment-position": "off",
"react/no-unused-prop-types": "off",
"no-negated-condition": "off",
"no-nested-ternary": "off",
"@babel/no-unused-expressions": "off",
"@typescript-eslint/ban-ts-comment": "off",
},
overrides: [
{
Expand Down
10 changes: 10 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,13 @@ ruby ">= 2.6.10"
gem 'cocoapods', '>= 1.13', '!= 1.15.0', '!= 1.15.1', '!= 1.15.2'
gem 'activesupport', '>= 6.1.7.5', '!= 7.1.0'
gem 'xcodeproj', '< 1.26.0'
gem 'concurrent-ruby', '< 1.3.4'

# Ruby 3.4.0 has removed some libraries from the standard library.
gem 'bigdecimal'
gem 'logger'
gem 'benchmark'
gem 'mutex_m'


source "https://rubygems.org"
7 changes: 7 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ GEM
json (>= 1.5.1)
atomos (0.1.3)
base64 (0.2.0)
benchmark (0.4.0)
bigdecimal (3.1.8)
claide (1.1.0)
cocoapods (1.14.3)
Expand Down Expand Up @@ -79,6 +80,7 @@ GEM
i18n (1.14.5)
concurrent-ruby (~> 1.0)
json (2.10.2)
logger (1.7.0)
minitest (5.23.1)
molinillo (0.8.0)
mutex_m (0.2.0)
Expand Down Expand Up @@ -111,7 +113,12 @@ PLATFORMS

DEPENDENCIES
activesupport (>= 6.1.7.5, != 7.1.0)
benchmark
bigdecimal
cocoapods (>= 1.13, != 1.15.2, != 1.15.1, != 1.15.0)
concurrent-ruby (< 1.3.4)
logger
mutex_m
xcodeproj (< 1.26.0)

RUBY VERSION
Expand Down
116 changes: 104 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
<a href="https://discord.gg/k2gzABTfav">Discord</a> •
<a href="https://shopify.github.io/flash-list/docs/">Getting started</a> •
<a href="https://shopify.github.io/flash-list/docs/usage">Usage</a> •
<a href="https://shopify.github.io/flash-list/docs/performance-troubleshooting">Performance</a> •
<a href="https://shopify.github.io/flash-list/docs/fundamentals/performant-components">Writing performant components</a> •
<a href="https://shopify.github.io/flash-list/docs/known-issues">Known Issues</a>
<br><br>
Expand All @@ -16,19 +15,33 @@ Swap from FlatList in seconds. Get instant performance.

</div>

## React Native's new architecture support
# FlashList v2

FlashList v1 is compatible with React Native's new architecture however, we have a new version (v2) in alpha that fully leverages the new architecture and comes with more features. Click [here](https://github.com/Shopify/flash-list/tree/new-rlv-prototype?tab=readme-ov-file#flashlist-v2) to know more.
FlashList v2 has been rebuilt from the ground up for RN's new architecture and delivers fast performance, higher precision, and better ease of use compared to v1. We've achieved all this while moving to a JS-only solution! One of the key advantages of FlashList v2 is that it doesn't require any estimates. It also introduces several new features compared to v1.

> ⚠️ **IMPORTANT:** FlashList v2.x has been designed to fully leverage the new architecture. **Old architecture will only be supported while FlashList v2 is in alpha/beta/rc and will be dropped once it's ready.** When run on old architecture, we just fall back to v1.x which doesn't have any of the new features.

### Is v2 production ready?

Yes, please use one of the release candidates if you want to ship to production `2.0.0-rc.x`. While we can make some changes in the final version, we expect release candidates to be quite stable. Use the alpha track if you want to test new changes quickly and don't mind occasional bugs.

> ⚠️ **IMPORTANT:** FlashList v2.x's alpha track moves quickly and can have some issues. Please report any issues or edge cases you run into. We're actively working on testing and optimizing v2. We also highly recommend using it with RN 0.78+ for optimal performance.

### Old architecture / FlashList v1

If you're running on old architecture or using FlashList v1.x, you can access the documentation specific to v1 here: [FlashList v1 Documentation](https://shopify.github.io/flash-list/docs/1.x/).

### Web support

FlashList v2 has web support. Most of the features should work but we're not actively testing it right now. If you run into an issue, please raise it on GitHub.

## Installation

Add the package to your project via `yarn add @shopify/flash-list` and run `pod install` in the `ios` directory.
Add the package to your project via `yarn add @shopify/flash-list@rc` and run `pod install` in the `ios` directory.

## Usage

We recommend reading the detailed documentation for using `FlashList` [here](https://shopify.github.io/flash-list/docs/usage).

But if you are familiar with [FlatList](https://reactnative.dev/docs/flatlist), you already know how to use `FlashList`. You can try out `FlashList` by changing the component name and adding the `estimatedItemSize` prop or refer to the example below:
But if you are familiar with [FlatList](https://reactnative.dev/docs/flatlist), you already know how to use `FlashList`. You can try out `FlashList` by changing the component name or refer to the example below:

```jsx
import React from "react";
Expand All @@ -49,20 +62,99 @@ const MyList = () => {
<FlashList
data={DATA}
renderItem={({ item }) => <Text>{item.title}</Text>}
estimatedItemSize={200}
/>
);
};
```

To avoid common pitfalls, you can also follow these steps for migrating from `FlatList`, based on our own experiences:
To avoid common pitfalls, you can also follow these steps for migrating from `FlatList`, based on our own experience:

1. Switch from `FlatList` to `FlashList` and render the list once. You should see a warning about missing `estimatedItemSize` and a suggestion. Set this value as the prop directly.
2. **Important**: Scan your [`renderItem`](https://shopify.github.io/flash-list/docs/usage/#renderitem) hierarchy for explicit `key` prop definitions and remove them. If you’re doing a `.map()` use indices as keys.
1. Simply from `FlatList` to `FlashList` and render the list.
2. **Important**: Scan your [`renderItem`](https://shopify.github.io/flash-list/docs/usage/#renderitem) hierarchy for explicit `key` prop definitions and remove them. If you’re doing a `.map()` use our hook called [`useMappingHelper`](https://shopify.github.io/flash-list/docs/usage/#usemappinghelper).
3. Check your [`renderItem`](https://shopify.github.io/flash-list/docs/usage/#renderitem) hierarchy for components that make use of `useState` and verify whether that state would need to be reset if a different item is passed to that component (see [Recycling](https://shopify.github.io/flash-list/docs/recycling))
4. If your list has heterogenous views, pass their types to `FlashList` using [`getItemType`](https://shopify.github.io/flash-list/docs/usage/#getitemtype) prop to improve performance.
5. Do not test performance with JS dev mode on. Make sure you’re in release mode. `FlashList` can appear slower while in dev mode due to a small render buffer.
6. Memoizing props passed to FlashList is more important in v2. v1 was more selective about updating items, but this was often perceived as a bug by developers. We will not follow that approach and will instead allow developers to ensure that props are memoized. We will stop re-renders of children wherever it is obvious.

## Other things to know

- `keyExtractor` is important to prevent glitches due to item layout changes when going upwards. We highly recommend having a valid `keyExtractor` with v2.
- `useLayoutState`: This is similar to `useState` but communicates the change in state to FlashList. It's useful if you want to resize a child component based on a local state. Item layout changes will still be detected using `onLayout` callback in the absence of `useLayoutState`, which might not look as smooth on a case-by-case basis.

```jsx
import { useLayoutState } from "@shopify/flash-list";

const MyItem = ({ item }) => {
const [isExpanded, setIsExpanded] = useLayoutState(false);
const height = isExpanded ? 150 : 80;

return (
<Pressable onPress={() => setIsExpanded(!isExpanded)}>
<View style={{ height, padding: 16 }}>
<Text>{item.title}</Text>
</View>
</Pressable>
);
};
```

- `useRecyclingState`: Similar to `useState` but accepts a dependency array. On change of deps, the state gets reset without an additional `setState` call. Useful for maintaining local item state if really necessary. It also has the functionality of `useLayoutState` built in.

```jsx
import { useRecyclingState } from "@shopify/flash-list";

const GridItem = ({ item }) => {
const [isExpanded, setIsExpanded] = useRecyclingState(
false,
[item.id],
() => {
// runs on reset. Can be used to reset scroll positions of nested horizontal lists
}
);
const height = isExpanded ? 100 : 50;

return (
<Pressable onPress={() => setIsExpanded(!isExpanded)}>
<View style={{ height, backgroundColor: item.color }}>
<Text>{item.title}</Text>
</View>
</Pressable>
);
};
```

- `useMappingHelper`: Returns a function that helps create optimal mapping keys for items when using `.map()` in your render methods. Using this ensures optimized recycling and performance for FlashList.

```jsx
import { useMappingHelper } from "@shopify/flash-list";

const MyComponent = ({ items }) => {
const { getMappingKey } = useMappingHelper();

return (
<FlashList
data={items}
renderItem={({ item }) => <ItemComponent item={item} />}
/>
);
};

// When mapping over items inside components:
const NestedList = ({ items }) => {
const { getMappingKey } = useMappingHelper();

return (
<View>
{items.map((item, index) => (
<Text key={getMappingKey(item.id, index)}>{item.title}</Text>
))}
</View>
);
};
```

- If you're nesting horizontal FlashLists in vertical lists, we highly recommend the vertical list to be FlashList too. We have optimizations to wait for child layout to complete which can improve load times.

## App / Playground

The [fixture](https://github.com/Shopify/flash-list/tree/main/fixture) is an example app showing how to use the library.
The [fixture](./fixture/) is an example app showing how to use the library.
72 changes: 42 additions & 30 deletions documentation/docs/fundamentals/performant-components.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
---
id: performant-components
title: Writing performant components
id: performance
title: Performance
---

## Profiling

:::warning
Before assessing your list's performance, make sure you are in release mode. On Android, you can disable JS dev mode inside the developer menu, whereas you need to run the release configuration on iOS.
FlashList can appear to be slower than FlatList in dev mode. The primary reason is a much smaller and fixed [window size](https://reactnative.dev/docs/virtualizedlist#windowsize) equivalent. Click [here](https://reactnative.dev/docs/performance#running-in-development-mode-devtrue) to know more about why you shouldn't profile with dev mode on.
:::

Memoizing props passed to FlashList is more important in v2. v1 was more selective about updating items, but this was often perceived as a bug by developers. We will not follow that approach and will instead allow developers to ensure that props are memoized. We will stop re-renders of children wherever it is obvious.

# Writing Performant Components

While `FlashList` does its best to achieve high performance, it will still perform poorly if your item components are slow to render. In this post, let's dive deeper into how you can remedy this.

## Recycling
Expand All @@ -11,16 +22,12 @@ One important thing to understand is how `FlashList` works under the hood. When

## Optimizations

There's lots of optimizations that are applicable for _any_ React Native component and which might help render times of your item components as well. Usage of `useCallback`, `useMemo`, and `useRef` is advised - but don't use these blindly, always [measure the performance](/performance-troubleshooting) before and after making your changes.
There's lots of optimizations that are applicable for _any_ React Native component and which might help render times of your item components as well. Usage of `useCallback`, `useMemo`, and `useRef` is advised - but don't use these blindly, always measure the performance before and after making your changes.

:::note
Always profile performance in the release mode. `FlashList`'s performance between JS dev and release mode differs greatly.
:::

### `estimatedItemSize`

Ensure [`estimatedItemSize`](/usage#estimateditemsize) is as close as possible to the real average value - see [here](/estimated-item-size#how-to-calculate) how to properly calculate the value for this prop.

### Remove `key` prop

:::warning
Expand All @@ -29,6 +36,10 @@ Using `key` prop inside your item and item's nested components will highly degra

Make sure your **item components and their nested components don't have a `key` prop**. Using this prop will lead to `FlashList` not being able to recycle views, losing all the benefits of using it over `FlatList`.

#### Why are keys harmful to FlashList?

FlashList's core performance advantage comes from **recycling** components instead of creating and destroying them however, when you add a `key` prop that changes between different data items, React treats the component as entirely different and forces a complete re-creation of the component tree.

For example, if we had a following item component:

```tsx
Expand All @@ -46,7 +57,7 @@ const MyItem = ({ item }) => {
};
```

Then the `key` prop should be removed from both `MyItem` and `MyNestedComponent`:
Then the `key` prop should be removed from both `MyItem` and `MyNestedComponent`. It isn't needed and react can alredy take care of updating the components.

```tsx
const MyNestedComponent = ({ item }) => {
Expand All @@ -63,38 +74,38 @@ const MyItem = ({ item }) => {
};
```

There might be cases where React forces you to use `key` prop, such as when using `map`. In such cirumstances, ensure that the `key` is not tied to the `item` prop in any way, so the keys don't change when recycling.

Let's imagine we want to display names of users:
There might be cases where React forces you to use `key` prop, such as when using `map`. In such circumstances, **use `useMappingHelper`** to ensure optimal performance:

```tsx
const MyItem = ({ item }: { item: any }) => {
return (
<>
{item.users.map((user: any) => {
<Text key={user.id}>{user.name}</Text>;
})}
</>
);
};
```
import { useMappingHelper } from "@shopify/flash-list";

If we wrote our item component like this, the `Text` component would need to be re-created. Instead, we can do the following:

```tsx
const MyItem = ({ item }) => {
const { getMappingKey } = useMappingHelper();

return (
<>
{item.users.map((user, index) => {
/* eslint-disable-next-line react/no-array-index-key */
<Text key={index}>{user.name}</Text>;
})}
{item.users.map((user, index) => (
<Text key={getMappingKey(user.id, index)}>{user.name}</Text>
))}
</>
);
};
```

Although using index as a `key` in `map` is not recommended by React, in this case since the data is derived from the list's data, the items will update correctly.
The `useMappingHelper` hook intelligently provides the right key strategy:

- **When inside FlashList**: Uses stable keys that don't change during recycling
- **When outside FlashList**: Uses the provided item key for proper React reconciliation

This approach ensures that:

- Components can be recycled properly within FlashList
- React's reconciliation works correctly
- Performance remains optimal

:::info
`useMappingHelper` should be used whenever you need to map over arrays inside FlashList item components. It automatically handles the complexity of providing recycling-friendly keys.
:::

### Difficult calculations

Expand Down Expand Up @@ -182,8 +193,9 @@ const MyHeavyComponent = () => {
return ...;
};

const MemoizedMyHeavyComponent = memo(MyHeavyComponent);

const MyItem = ({ item }: { item: any }) => {
const MemoizedMyHeavyComponent = memo(MyHeavyComponent);
return (
<>
<MemoizedMyHeavyComponent />
Expand Down
14 changes: 5 additions & 9 deletions documentation/docs/fundamentals/recycling.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,14 @@ title: Recycling
slug: /recycling
---

One important thing to understand is how `FlashList` works under the hood. When an item gets out of the viewport, instead of being destroyed, the component is re-rendered with a different `item` prop. For example, if you make use of `useState` in a reused component, you may see state values that were set for that component when it was associated with a different item in the list, and would then need to reset any previously set state when a new item is rendered:
One important thing to understand is how `FlashList` works under the hood. When an item gets out of the viewport, instead of being destroyed, the component is re-rendered with a different `item` prop. For example, if you make use of `useState` in a reused component, you may see state values that were set for that component when it was associated with a different item in the list, and would then need to reset any previously set state when a new item is rendered. FlashList now comes with `useRecyclingState` hook that can reet the state automatically without an additional render.

```tsx
const MyItem = ({ item }) => {
const lastItemId = useRef(item.someId);
const [liked, setLiked] = useState(item.liked);
if (item.someId !== lastItemId.current) {
lastItemId.current = item.someId;
setLiked(item.liked);
}
// value of liked is reset if deps array changes. The hook also accepts a callback to reset anything else if required.
const [liked, setLiked] = useRecyclingState(item.liked, [item.someId], () => {
// callback
});

return (
<Pressable onPress={() => setLiked(true)}>
Expand All @@ -23,6 +21,4 @@ const MyItem = ({ item }) => {
};
```

This follows advice in the [React Hooks FAQ on implementing getDerivedStateFromProps](https://reactjs.org/docs/hooks-faq.html#how-do-i-implement-getderivedstatefromprops). Ideally your component hierarchy returned from [renderItem](../fundamentals/usage.md#renderitem) should not make use of `useState` for best performance.

When optimizing your item component, try to ensure as few things as possible have to be re-rendered and recomputed when recycling.
Loading
Loading