You add filters and sorting by handing the list a different array, and the array is the part everyone gets wrong.
A filter is a derived array. A sort is a derived array. You compute one from your data and pass it to the list, and on a phone that is genuinely all the mechanism there is. Two documented rules decide whether it works. React Native's FlatList is a PureComponent, so it redraws when the array you pass is a different object and not when the contents of the same object change, which is why filtering appears to work for free and sorting appears to be broken. And Apple does not have a page about filter controls at all. It documents filtering as a scope bar attached to a search field, and it says where that field goes. If you are starting further back than this, begin with make an app.
What follows is the re-render rule and the four ways to trip over it, the props React Native lists for keeping a long list fast, where Apple puts a filter control on an iPhone, and the two numbers Apple does give you about how many options a control should hold. Every claim comes from React Native or Apple documentation, read on 23 October 2026, with the page named each time.
Start hereThe short version
Copy the array before you sort it, and put the control above the list.
Those two sentences cover most of the work. Filter returns a new array, so a filtered list updates on its own. Sort returns the array you gave it, so a sorted list sits there looking stale until you copy first. Anything the rows depend on that is not inside the array goes in extraData. Keys come from your data, never from the position, because the position is the thing sorting changes.
The placement half has fewer rules than people expect. Apple has no Filters page and no Sorting page. What it has is a scope bar, documented as a control for filtering and adjusting the scope of a search, and clear guidance on where the search field itself belongs. For one list in one view, that is an inline field sitting above the list, pinned to the top toolbar when the list scrolls.
What does React Native say about re-rendering a list when the data changes?
It says the list compares references, not contents. The FlatList reference puts the whole rule in two sentences: this is a PureComponent, which means it will not re-render if props remain shallow-equal, so make sure that everything your renderItem function depends on is passed as a prop that is not identical after updates, or your UI may not update on changes. It then names the two things people forget, the data prop and parent component state. That page prints its own last updated date of 19 October 2026 in the footer.
Read that against the two JavaScript methods you are about to use and the asymmetry falls out. Filter builds a new array, so the prop is a different object and the list redraws. Sort works in place and returns the array it was given, so the prop is the same object and the list does not. Push behaves like sort. This is the entire reason that a developer new to React Native will tell you filtering was trivial and sorting took an afternoon, when the two are the same amount of code.
For anything the rows read that is not in the array, React Native gives you extraData, described as a marker property for telling the list to re-render, with the instruction that if your renderItem, header or footer functions depend on anything outside the data prop you put it there and treat it immutably. A selected sort direction is the common case. There is a trap in the sequencing: while renderItem is defined inline it is recreated on every render, so the rows update anyway and the bug stays hidden until you memoise renderItem for performance and the rows go quiet.
One more caveat from the same reference, because it bites filter bars specifically. Internal state is not preserved when content scrolls out of the render window, and the documentation tells you to capture all your data in the item data or an external store. So a tick box or an expanded row cannot keep its state inside the row component. A list whose rows change under you has the same requirement for the same reason, which is the point where this and add activity feed turn out to be one problem.
Does the list notice
Six ways a filter changes, and whether the list redraws
Pick what you changed. Four of these six leave the screen exactly as it was, and in every case the reason is the same rule read from a different angle. The rule is in React Native's FlatList reference, which prints a last updated date of 19 October 2026 in its own footer.
Nothing happens on screen.
Array.prototype.sort sorts in place and hands you back the same array. The reference is identical, so the shallow compare passes and the list keeps the order it already had. The FlatList reference is blunt about the rule: everything renderItem depends on has to be passed as a prop that is not === after updates, and it names the data prop in that sentence. Copy before you sort.
Which props keep a filtered list fast?
Start with what the documentation does not claim. React Native has a page called Optimizing FlatList Configuration, and the word filter appears nowhere in its body. I checked on 23 October 2026. The same goes for sort and for search, although a plain grep of the HTML will tell you search appears twenty-two times, because the site's own search box and navigation furniture are in the markup. Every prop below is about virtualisation. They matter to a filter because changing one throws the rendered window away and rebuilds it, so a filter bar is a machine for making a list render from scratch over and over.
The page defines the symptom before it lists the cures, which is useful vocabulary when you are reading a bug report. Blank areas are what you see when the list cannot render items fast enough and you scroll into a part of it that has not been drawn. The window is the area where items are mounted, and it is normally much larger than the viewport. Nearly every number here is a trade between blank space and a button that answers slowly.
| Prop | Documented default | What it buys you |
|---|---|---|
| initialNumToRender | 10 | The initial amount of items to render. React Native says to define a precise number that covers the screen on every device, and warns that a low value leaves blank areas if it is too small to fill the viewport. The FlatList reference adds that these items are never unmounted by the windowing, which is what keeps scroll to top feeling instant. |
| maxToRenderPerBatch | 10 | How many items come in on each scroll. A bigger number means fewer blank areas and longer stretches of JavaScript that block presses. This is the knob that trades smooth scrolling against a button that answers late. |
| updateCellsBatchingPeriod | 50 ms | The delay between batch renders. Paired with the prop above it lets you choose more items less often, or fewer items more often. Less frequent batches cause blank areas, more frequent batches cause responsiveness problems. |
| windowSize | 21 | Measured in viewports, so 21 means ten above, ten below and the one you are looking at. Smaller saves memory and shows more blank space. This is the first number to cut on a cheap Android phone with a long filtered list. |
| removeClippedSubviews | true on Android, otherwise false | Detaches views outside the viewport from the native view hierarchy. React Native pairs it with an unusually frank warning: the implementation can have bugs such as missing content, mainly observed on iOS, and it does not save significant memory because the views are detached rather than deallocated. |
| getItemLayout | no default, you write it | If every row is the same height, this removes the async layout measurement. React Native calls it a very desirable optimisation technique, and the FlatList reference calls it a great performance boost for lists of several hundred items. Remember to include the separator height in the offset. |
| keyExtractor | item.key, then item.id, then the index | Used for caching and as the React key to track item re-ordering, which is the sentence that matters the moment you add sorting. If it falls back to the index, every row changes identity when the order changes. |
The row component carries the rest. React Native asks for basic components with little logic and little nesting, light components with thumbnails rather than full images, and memo around the row so it only redraws when its own props change. It also asks you to stop writing renderItem inline: move the function out of the returned JSX, wrap it in useCallback so it is not rebuilt every render, and the list stops treating every parent render as new work. Those four habits do more for a filtered list than any of the numbers above, because a filter change means re-rendering many rows at once.
Two honest caveats. The documentation on removeClippedSubviews warns that the implementation can have bugs such as missing content, mainly observed on iOS, and that it does not save significant memory because views are detached rather than deallocated. And getItemLayout only works if every row is the same height. React Native's advice if your rows vary and you still need the speed is to ask your design team whether the design can change, which is an unusually direct thing for documentation to say. A saved subset like add bookmarks is a filter with a stored predicate, so it inherits all of this.
Where does Apple say a filter control belongs on screen?
Attached to search, and above the list it applies to. The first thing to know is that Apple has no page about filters. The Components catalogue in the Human Interface Guidelines, read on 23 October 2026, lists five pages under Navigation and search: Path controls, Search fields, Sidebars, Tab bars and Token fields. There is no Filters page and no Sorting page in the catalogue at all. Filtering is documented inside Search fields, where a scope bar is defined as a control for filtering and adjusting the scope of a search, and a token as a visual representation of a search term that acts as a filter for any additional terms.
On placement, Apple is specific. For iOS it names three main places for the entry point to search: as a tab in a tab bar, in a toolbar at the bottom or top of the screen, or directly inline with content. Place it at the bottom if there is room, because that keeps it easy to reach, and the examples given are Settings where search is the only toolbar item, and Mail and Notes where it sits alongside other controls. Place it at the top when it matters to defer to content at the bottom of the screen or there is no bottom toolbar, with Wallet named as the case where passes stack at the bottom.
The inline field is the one that describes a filter over a single list, and the guidance for it is the closest thing to a rule you will find. Use it when the position of the field alongside the content it searches strengthens that relationship, and when you need to filter or search within a single view rather than globally. When it sits at the top, position it above the list it searches, and consider pinning it to the top toolbar when scrolling so it stays distinct from search that appears elsewhere. Apple's own example is the Music app, where the main search is a tab but the library has an inline field for filtering songs and albums.
For the scope bar itself there are two instructions worth copying. Consider letting people filter search results by including a scope bar in the search results content area, which puts it under the field and over the results rather than off in a separate screen. And default to a broader scope and let people refine it, because the broad scope shows the full set of available results and gives people a sense of where narrowing will take them. A filter bar that opens pre-narrowed hides data from someone who never set it.
Apple, Human Interface Guidelines, Search fields, change log dated 8 June 2026, read 23 October 2026
How should the sort control work, and how many options is too many?
Apple's documented example of a sort control sits on the Pull-down buttons page, and it is useful. The page suggests a Sort button that could use a menu to let people select an attribute to sort on, and notes that after someone chooses an item the menu closes and the app performs the action. It also gives a length rule that most people ignore: list at least three items, because somebody has to interact with the button before they can see what is inside it, and if you have only one or two options use something else, such as a button for an action or a toggle or switch for a selection. That change log is dated 14 September 2022.
Read sideways, that is a decision rule for the whole control. Two sort orders, newest and oldest, is a toggle. Four or five sort attributes is a menu. The menu also has a cost the page states plainly, which is that listing too many items slows people down because it takes longer to find a specific one, so a sort menu is not a place to put every column in your table.
For a row of filter chips, the number comes from the Segmented controls page, change log dated 21 June 2023. Limit the number of segments, it says, because too many are hard to parse and time-consuming to navigate, and aim for no more than about five to seven segments in a wide interface and no more than about five on iPhone. Two content rules go with it: use nouns or noun phrases for the labels, and prefer either text or images rather than a mix in one control. So five is the documented ceiling for a chip row on a phone, and the sixth option is a signal that you need a menu or a scope bar instead.
Newly is one way to get this built. You describe the screen in plain English and it writes a real React Native and Expo project you own, so the FlatList, the keyExtractor and the sort function are all in your own source and you can change the array handling described higher up this page. It is $25 a month with no free tier, with two-way GitHub sync, TestFlight uploads for iOS, Google Play internal testing and a standalone Android APK. It does not press submit on the App Store for you, because Apple requires the owner of the content to do that, and the mechanics of that step are in publish to app store.
Questions people ask about filtering and sorting a list
Because sort does not give you a new array. FlatList implements PureComponent, and React Native documents the consequence directly: it will not re-render if props remain shallow-equal, so everything your renderItem function depends on has to be passed as a prop that is not === after updates, and that sentence names the data prop and parent component state. Array.prototype.sort sorts in place and returns the same array, so the reference never changes and the shallow compare passes. Copy the array first, then sort the copy. Filter has the opposite behaviour and returns a new array, which is why filtering appears to work for free. Read from the FlatList reference, last updated 19 October 2026.
Write down the five filters that matter, in order.
Five, because that is the number Apple gives for a chip row on an iPhone, and the act of cutting your list to five is most of the design work. Add the one sort order people actually ask for and you have the brief for the screen.
Start building