スキル一覧に戻る
TheBushidoCollective

jutsu-react-nativereact-native-performance

by TheBushidoCollective

A curated marketplace of Claude Code plugins that embody the principles of ethical and professional software development.

60🍴 6📅 2026年1月24日
GitHubで見るManusで実行

SKILL.md


name: jutsu-react-native:react-native-performance description: Use when optimizing React Native app performance. Covers FlatList optimization, memoization, image optimization, bundle size reduction, and profiling techniques. allowed-tools:

  • Read
  • Write
  • Edit
  • Bash
  • Grep
  • Glob

React Native Performance

Use this skill when optimizing React Native applications for better performance, faster load times, and smoother user experiences.

Key Concepts

List Performance

Optimize FlatList for large datasets:

import React, { useCallback } from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';

interface Item {
  id: string;
  title: string;
}

const ItemComponent = React.memo(({ item }: { item: Item }) => (
  <View style={styles.item}>
    <Text>{item.title}</Text>
  </View>
));

function OptimizedList({ data }: { data: Item[] }) {
  const renderItem = useCallback(
    ({ item }: { item: Item }) => <ItemComponent item={item} />,
    []
  );

  const keyExtractor = useCallback((item: Item) => item.id, []);

  const getItemLayout = useCallback(
    (data: any, index: number) => ({
      length: 80, // Fixed item height
      offset: 80 * index,
      index,
    }),
    []
  );

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      getItemLayout={getItemLayout}
      // Performance optimizations
      removeClippedSubviews={true}
      maxToRenderPerBatch={10}
      updateCellsBatchingPeriod={50}
      initialNumToRender={10}
      windowSize={5}
    />
  );
}

const styles = StyleSheet.create({
  item: {
    height: 80,
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#eee',
  },
});

Component Memoization

Use React.memo and useMemo:

import React, { useMemo } from 'react';
import { View, Text } from 'react-native';

interface UserCardProps {
  user: {
    id: string;
    name: string;
    email: string;
  };
  onPress: () => void;
}

// Memoize component to prevent unnecessary re-renders
const UserCard = React.memo(({ user, onPress }: UserCardProps) => {
  return (
    <View>
      <Text>{user.name}</Text>
      <Text>{user.email}</Text>
    </View>
  );
});

// Memoize expensive computations
function UserList({ users }: { users: User[] }) {
  const sortedUsers = useMemo(() => {
    return [...users].sort((a, b) => a.name.localeCompare(b.name));
  }, [users]);

  return (
    <View>
      {sortedUsers.map(user => (
        <UserCard key={user.id} user={user} onPress={() => {}} />
      ))}
    </View>
  );
}

Image Optimization

Optimize image loading and caching:

import React from 'react';
import { Image, View } from 'react-native';
import FastImage from 'react-native-fast-image';

// Use FastImage for better performance
function OptimizedImage({ uri }: { uri: string }) {
  return (
    <FastImage
      style={{ width: 200, height: 200 }}
      source={{
        uri,
        priority: FastImage.priority.normal,
        cache: FastImage.cacheControl.immutable,
      }}
      resizeMode={FastImage.resizeMode.cover}
    />
  );
}

// Lazy load images
function LazyImage({ uri }: { uri: string }) {
  return (
    <Image
      source={{ uri }}
      style={{ width: 200, height: 200 }}
      resizeMode="cover"
      loadingIndicatorSource={require('./placeholder.png')}
    />
  );
}

Best Practices

Use useCallback for Event Handlers

Prevent unnecessary re-renders:

import React, { useCallback, useState } from 'react';
import { View, Button, Text } from 'react-native';

function Counter() {
  const [count, setCount] = useState(0);

  // Bad - Creates new function on every render
  // const increment = () => setCount(count + 1);

  // Good - Memoized callback
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <View>
      <Text>{count}</Text>
      <Button title="Increment" onPress={increment} />
    </View>
  );
}

Virtualized Lists Only

Use FlatList/SectionList for scrollable content:

// Bad - ScrollView with map (renders all items)
<ScrollView>
  {items.map(item => (
    <ItemComponent key={item.id} item={item} />
  ))}
</ScrollView>

// Good - FlatList (virtualizes items)
<FlatList
  data={items}
  keyExtractor={item => item.id}
  renderItem={({ item }) => <ItemComponent item={item} />}
/>

Avoid Anonymous Functions in Render

// Bad - Creates new function on every render
<FlatList
  data={items}
  renderItem={({ item }) => (
    <TouchableOpacity onPress={() => console.log(item.id)}>
      <Text>{item.title}</Text>
    </TouchableOpacity>
  )}
/>

// Good - Memoized render function
const renderItem = useCallback(({ item }: { item: Item }) => (
  <ItemRow item={item} onPress={handleItemPress} />
), [handleItemPress]);

<FlatList
  data={items}
  renderItem={renderItem}
/>

Optimize Bundle Size

Reduce JavaScript bundle size:

# Analyze bundle
npx react-native-bundle-visualizer

# Enable Hermes engine (app.json for Expo)
{
  "expo": {
    "jsEngine": "hermes"
  }
}

# Enable Hermes (android/app/build.gradle for bare React Native)
project.ext.react = [
  enableHermes: true
]

# Use ProGuard for Android (android/app/build.gradle)
def enableProguardInReleaseBuilds = true

Code Splitting

Split code for faster initial load:

import React, { lazy, Suspense } from 'react';
import { View, ActivityIndicator } from 'react-native';

// Lazy load heavy components
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<ActivityIndicator />}>
      <HeavyComponent />
    </Suspense>
  );
}

Common Patterns

import React, { useState, useCallback, useEffect } from 'react';
import { TextInput, FlatList } from 'react-native';

function SearchableList({ data }: { data: Item[] }) {
  const [query, setQuery] = useState('');
  const [debouncedQuery, setDebouncedQuery] = useState('');

  // Debounce search
  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedQuery(query);
    }, 300);

    return () => clearTimeout(timer);
  }, [query]);

  const filteredData = useMemo(() => {
    if (!debouncedQuery) return data;
    return data.filter(item =>
      item.title.toLowerCase().includes(debouncedQuery.toLowerCase())
    );
  }, [data, debouncedQuery]);

  return (
    <>
      <TextInput
        value={query}
        onChangeText={setQuery}
        placeholder="Search..."
      />
      <FlatList
        data={filteredData}
        keyExtractor={item => item.id}
        renderItem={({ item }) => <ItemComponent item={item} />}
      />
    </>
  );
}

Optimized Animations

Use react-native-reanimated for smooth animations:

import React from 'react';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';
import { Pressable } from 'react-native';

function AnimatedButton() {
  const scale = useSharedValue(1);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  const handlePressIn = () => {
    scale.value = withSpring(0.95);
  };

  const handlePressOut = () => {
    scale.value = withSpring(1);
  };

  return (
    <Pressable onPressIn={handlePressIn} onPressOut={handlePressOut}>
      <Animated.View style={[styles.button, animatedStyle]}>
        <Text>Press Me</Text>
      </Animated.View>
    </Pressable>
  );
}

Pagination

Implement efficient pagination:

import React, { useState, useCallback } from 'react';
import { FlatList, ActivityIndicator } from 'react-native';

function PaginatedList() {
  const [data, setData] = useState<Item[]>([]);
  const [loading, setLoading] = useState(false);
  const [page, setPage] = useState(1);

  const loadMore = useCallback(async () => {
    if (loading) return;

    setLoading(true);
    const newData = await fetchData(page);
    setData(prev => [...prev, ...newData]);
    setPage(p => p + 1);
    setLoading(false);
  }, [loading, page]);

  const renderItem = useCallback(
    ({ item }: { item: Item }) => <ItemComponent item={item} />,
    []
  );

  const renderFooter = () => {
    if (!loading) return null;
    return <ActivityIndicator style={{ margin: 16 }} />;
  };

  return (
    <FlatList
      data={data}
      renderItem={renderItem}
      keyExtractor={item => item.id}
      onEndReached={loadMore}
      onEndReachedThreshold={0.5}
      ListFooterComponent={renderFooter}
    />
  );
}

Memoized Selector

import React, { useMemo } from 'react';
import { View, Text } from 'react-native';

interface User {
  id: string;
  name: string;
  age: number;
  active: boolean;
}

function UserStats({ users }: { users: User[] }) {
  const stats = useMemo(() => {
    return {
      total: users.length,
      active: users.filter(u => u.active).length,
      averageAge: users.reduce((sum, u) => sum + u.age, 0) / users.length,
    };
  }, [users]);

  return (
    <View>
      <Text>Total: {stats.total}</Text>
      <Text>Active: {stats.active}</Text>
      <Text>Average Age: {stats.averageAge.toFixed(1)}</Text>
    </View>
  );
}

Image Preloading

import { Image } from 'react-native';

async function preloadImages(imageUrls: string[]) {
  const promises = imageUrls.map(url =>
    Image.prefetch(url)
  );

  await Promise.all(promises);
}

// Usage
useEffect(() => {
  preloadImages([
    'https://example.com/image1.jpg',
    'https://example.com/image2.jpg',
  ]);
}, []);

Anti-Patterns

Don't Use console.log in Production

// Bad - Logs slow down production
console.log('User data:', user);

// Good - Remove or use __DEV__
if (__DEV__) {
  console.log('User data:', user);
}

Don't Inline Large Objects

// Bad - Creates new object on every render
<Component
  style={{ width: 100, height: 100, backgroundColor: '#fff' }}
  config={{ option1: true, option2: false }}
/>

// Good - Use StyleSheet and constants
const styles = StyleSheet.create({
  component: { width: 100, height: 100, backgroundColor: '#fff' },
});

const config = { option1: true, option2: false };

<Component style={styles.component} config={config} />

Don't Forget to Clean Up

// Bad - Memory leak
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);
}, []);

// Good - Clean up
useEffect(() => {
  const timer = setInterval(() => {
    console.log('Tick');
  }, 1000);

  return () => clearInterval(timer);
}, []);

Don't Use setState in Loops

// Bad - Multiple re-renders
items.forEach(item => {
  setData(prev => [...prev, item]);
});

// Good - Single update
setData(prev => [...prev, ...items]);

Profiling Tools

React DevTools Profiler

import { Profiler } from 'react';

function onRenderCallback(
  id: string,
  phase: 'mount' | 'update',
  actualDuration: number
) {
  console.log(`${id} (${phase}) took ${actualDuration}ms`);
}

<Profiler id="MyComponent" onRender={onRenderCallback}>
  <MyComponent />
</Profiler>

Performance Monitor

import { PerformanceObserver, performance } from 'perf_hooks';

// Enable performance monitor
if (__DEV__) {
  const observer = new PerformanceObserver((list) => {
    list.getEntries().forEach((entry) => {
      console.log(`${entry.name}: ${entry.duration}ms`);
    });
  });

  observer.observe({ entryTypes: ['measure'] });
}
  • react-native-components: Building performant components
  • react-native-navigation: Optimizing navigation performance
  • react-native-native-modules: Native performance optimization

スコア

総合スコア

70/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

+10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

レビュー

💬

レビュー機能は近日公開予定です