Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Build performant React Native and Expo apps with best practices for lists, animations, and navigation
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/scroll-position-no-state.md
1---2title: Never Track Scroll Position in useState3impact: HIGH4impactDescription: prevents render thrashing during scroll5tags: scroll, performance, reanimated, useRef6---78## Never Track Scroll Position in useState910Never store scroll position in `useState`. Scroll events fire rapidly—state11updates cause render thrashing and dropped frames. Use a Reanimated shared value12for animations or a ref for non-reactive tracking.1314**Incorrect (useState causes jank):**1516```tsx17import { useState } from 'react'18import {19ScrollView,20NativeSyntheticEvent,21NativeScrollEvent,22} from 'react-native'2324function Feed() {25const [scrollY, setScrollY] = useState(0)2627const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {28setScrollY(e.nativeEvent.contentOffset.y) // re-renders on every frame29}3031return <ScrollView onScroll={onScroll} scrollEventThrottle={16} />32}33```3435**Correct (Reanimated for animations):**3637```tsx38import Animated, {39useSharedValue,40useAnimatedScrollHandler,41} from 'react-native-reanimated'4243function Feed() {44const scrollY = useSharedValue(0)4546const onScroll = useAnimatedScrollHandler({47onScroll: (e) => {48scrollY.value = e.contentOffset.y // runs on UI thread, no re-render49},50})5152return (53<Animated.ScrollView54onScroll={onScroll}55// higher number has better performance, but it fires less often.56// unset this if you need higher precision over performance.57scrollEventThrottle={16}58/>59)60}61```6263**Correct (ref for non-reactive tracking):**6465```tsx66import { useRef } from 'react'67import {68ScrollView,69NativeSyntheticEvent,70NativeScrollEvent,71} from 'react-native'7273function Feed() {74const scrollY = useRef(0)7576const onScroll = (e: NativeSyntheticEvent<NativeScrollEvent>) => {77scrollY.current = e.nativeEvent.contentOffset.y // no re-render78}7980return <ScrollView onScroll={onScroll} scrollEventThrottle={16} />81}82```83