React Native Reanimated 4 ב-2026: מדריך מלא לאנימציות עם Worklets ו-CSS

מדריך מעשי ל-React Native Reanimated 4 ב-2026: Worklets, CSS Animations, Shared Element Transitions ו-Layout Animations — עם דוגמאות קוד אמיתיות, מדריך מיגרציה מ-Reanimated 3 וטיפים לביצועים של 60+ FPS.

React Native Reanimated 4: אנימציות 60FPS 2026

בואו נודה בזה — בשנת 2026, אנימציות הן כבר לא איזו "תוספת ויזואלית" נחמדה. הן חלק בלתי נפרד מחוויית המשתמש המודרנית, ואם האפליקציה שלכם מקרטעת ב-30 FPS, המשתמשים פשוט יורדים ממנה. נקודה. React Native Reanimated 4, שהשתחררה לסטייבל בסוף 2025, מביאה איתה שורה של חידושים שמשנים לחלוטין את האופן שבו אנחנו בונים אנימציות באפליקציות React Native: תמיכה ב-CSS Animations, Layout Animations משופרות, Shared Element Transitions, ו-Worklets חדשניים שרצים על UI Thread במהירות מקסימלית.

במדריך הזה תלמדו את כל מה שצריך לדעת כדי לבנות אנימציות חלקות בקצב של 60+ FPS ב-React Native 2026 — החל מהיסודות של Reanimated 4 ועד טכניקות מתקדמות שיהפכו את האפליקציה שלכם לזריזה ומקצועית. כל הדוגמאות מבוססות על Reanimated 4.1.x, React Native 0.78 והארכיטקטורה החדשה (Bridgeless Mode). בואו נצלול פנימה.

אז מה חדש ב-Reanimated 4 בהשוואה לגרסה 3?

בכנות? Reanimated 4 הייתה כתיבה מחדש כמעט מלאה של החלק התחתון של הספרייה. המטרה: לנצל את היתרונות של ה-New Architecture של React Native (JSI, Fabric, TurboModules). בניגוד ל-Reanimated 3, שעוד הייתה תאימה גם ל-Bridge הישן, גרסה 4 דורשת New Architecture. בתמורה — הביצועים פשוט בליגה אחרת.

החידושים המרכזיים

  • CSS Animations API: תמיכה מלאה בסינטקס דמוי-CSS עם animationName, transition ו-keyframes.
  • Worklets 2.0: מנוע Worklets חדש עם תמיכה ב-async/await ו-Generators (סוף סוף!).
  • Shared Element Transitions: עברו ל-API יציב, ועובד מצוין עם Expo Router ו-React Navigation 7.
  • Layout Animations: אנימציות אוטומטיות לשינויי לייאאוט בלי הצורך ב-LayoutAnimation מה-Core.
  • Reduced Motion Detection: תמיכה אוטומטית בהעדפות נגישות של המשתמש.
  • תמיכה ב-Web: אותו קוד רץ ב-iOS, Android ו-React Native Web — עם CSS אמיתי תחת המכסה.
  • שיפורי ביצועים: שיפור של עד 40% בזמן אתחול אנימציה, ופחות זיכרון.

התקנה והגדרה ראשונית

דרישות מקדימות

לפני שמתקינים, ודאו שהפרויקט עומד בדרישות הבאות. אני יודע, רשימה ארוכה, אבל זה משתלם:

  • React Native 0.78 ומעלה (או Expo SDK 53+)
  • New Architecture מופעל (newArchEnabled: true)
  • React 19+
  • Node.js 20 LTS
  • Xcode 16 (ל-iOS) ו-Android Gradle Plugin 8.5+

התקנה בפרויקט Expo

npx expo install react-native-reanimated@~4.1.0
npx expo prebuild --clean

התקנה בפרויקט Bare React Native

npm install react-native-reanimated@^4.1.0
cd ios && pod install && cd ..

הגדרת Babel Plugin

הוסיפו את הפלאגין של Reanimated לקובץ babel.config.js שלכם. חשוב מאוד: הפלאגין חייב להיות האחרון ברשימה. שכחתי את זה פעם אחת — הקדשתי שעה לדיבאג. אל תהיו אני.

module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      'react-native-reanimated/plugin', // Must be last!
    ],
  };
};

הבנת Worklets — הלב של Reanimated

Worklet זו פונקציית JavaScript ש-Reanimated מעבירה לרוץ על ה-UI Thread במקום על JS Thread. למה זה חשוב? כי זה מאפשר לאנימציה להיות חלקה ב-60 FPS גם כש-JS Thread שלכם תקוע במשימות אחרות (כמו פענוח JSON ענק או רינדור רשימה).

כתיבת Worklet ראשון

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

export default function BounceBox() {
  const scale = useSharedValue(1);

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

  const handlePress = () => {
    scale.value = withSpring(scale.value === 1 ? 1.5 : 1, {
      damping: 10,
      stiffness: 100,
    });
  };

  return (
    <Pressable onPress={handlePress}>
      <Animated.View
        style={[
          { width: 100, height: 100, backgroundColor: '#3b82f6', borderRadius: 12 },
          animatedStyle,
        ]}
      />
    </Pressable>
  );
}

שימו לב להוראת 'worklet' בתחילת הפונקציה — זה אומר ל-Babel Plugin של Reanimated להפוך את הפונקציה ל-worklet שירוץ על ה-UI Thread. בלי זה, הקוד פשוט יקרוס.

CSS Animations API — החדש והנוצץ ב-Reanimated 4

אחד החידושים הכי משמעותיים ב-Reanimated 4 הוא תמיכה מלאה בסינטקס דמוי-CSS. זה מאפשר לכם לכתוב אנימציות בצורה הצהרתית פשוטה, בלי הצורך ב-shared values עבור מקרים בסיסיים. אם אתם מגיעים מרקע ווב — תרגישו בבית מיד.

שימוש ב-transition

import Animated from 'react-native-reanimated';
import { useState } from 'react';
import { Pressable, Text } from 'react-native';

export default function CSSTransitionExample() {
  const [active, setActive] = useState(false);

  return (
    <Pressable onPress={() => setActive(!active)}>
      <Animated.View
        style={{
          width: active ? 200 : 100,
          height: 100,
          backgroundColor: active ? '#10b981' : '#3b82f6',
          borderRadius: active ? 50 : 12,
          transitionProperty: ['width', 'backgroundColor', 'borderRadius'],
          transitionDuration: '300ms',
          transitionTimingFunction: 'ease-in-out',
        }}
      >
        <Text style={{ color: '#fff', textAlign: 'center', lineHeight: 100 }}>
          לחצו אותי
        </Text>
      </Animated.View>
    </Pressable>
  );
}

שימוש ב-keyframes ו-animationName

import Animated, { keyframes } from 'react-native-reanimated';

const pulse = keyframes({
  from: { opacity: 1, transform: [{ scale: 1 }] },
  '50%': { opacity: 0.5, transform: [{ scale: 1.1 }] },
  to: { opacity: 1, transform: [{ scale: 1 }] },
});

export default function PulseLoader() {
  return (
    <Animated.View
      style={{
        width: 60,
        height: 60,
        borderRadius: 30,
        backgroundColor: '#ef4444',
        animationName: pulse,
        animationDuration: '1.5s',
        animationIterationCount: 'infinite',
      }}
    />
  );
}

היתרון הגדול: הקוד הזה רץ אותו דבר ב-React Native Web עם CSS אמיתי, וב-iOS/Android עם המנוע של Reanimated. כתבו פעם אחת, רוצו בכל מקום (סוף סוף, באמת).

Layout Animations — אנימציות אוטומטיות (וקסם אמיתי)

Layout Animations מאפשרות לכם להוסיף, להסיר או להזיז רכיבים עם אנימציה אוטומטית — בלי לכתוב logic בעצמכם. ב-Reanimated 4, זה הרבה יותר חזק וגמיש מהגרסאות הקודמות.

FadeIn ו-FadeOut בסיסיים

import Animated, { FadeIn, FadeOut, Layout } from 'react-native-reanimated';
import { useState } from 'react';
import { Button, View, Text } from 'react-native';

export default function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: 'ללמוד Reanimated 4' },
    { id: 2, text: 'לבנות אפליקציה מדהימה' },
  ]);

  const removeTodo = (id) => setTodos(todos.filter((t) => t.id !== id));

  return (
    <View style={{ padding: 16 }}>
      {todos.map((todo) => (
        <Animated.View
          key={todo.id}
          entering={FadeIn.duration(300)}
          exiting={FadeOut.duration(200)}
          layout={Layout.springify()}
          style={{ padding: 12, backgroundColor: '#f3f4f6', marginBottom: 8, borderRadius: 8 }}
        >
          <Text>{todo.text}</Text>
          <Button title="הסר" onPress={() => removeTodo(todo.id)} />
        </Animated.View>
      ))}
    </View>
  );
}

אנימציות מותאמות אישית

import Animated, { SlideInRight, SlideOutLeft, FadingTransition } from 'react-native-reanimated';

// Custom entering animation
const customEnter = SlideInRight.springify().damping(15).stiffness(120);

// Custom exit
const customExit = SlideOutLeft.duration(250);

// Custom layout transition
const customLayout = FadingTransition.duration(400);

Shared Element Transitions

Shared Element Transitions היא, לדעתי, אחד הפיצ'רים הכי מרשימים ב-Reanimated 4 — אנימציות חלקות בין מסכים, בדיוק כמו שרואים באפליקציות נייטיב מובילות (חשבו על Apple Photos או Instagram). ב-2026, סוף סוף, הפיצ'ר הזה עובד באופן מלא עם Expo Router ו-React Navigation 7.

דוגמה: מעבר מרשימה למסך פרטים

// app/index.tsx
import { Link } from 'expo-router';
import Animated from 'react-native-reanimated';
import { View, Text, Pressable } from 'react-native';

const products = [
  { id: '1', title: 'מוצר ראשון', image: 'https://example.com/1.jpg' },
  { id: '2', title: 'מוצר שני', image: 'https://example.com/2.jpg' },
];

export default function ProductList() {
  return (
    <View>
      {products.map((product) => (
        <Link key={product.id} href={`/product/${product.id}`} asChild>
          <Pressable>
            <Animated.Image
              sharedTransitionTag={`product-image-${product.id}`}
              source={{ uri: product.image }}
              style={{ width: 100, height: 100, borderRadius: 8 }}
            />
            <Animated.Text sharedTransitionTag={`product-title-${product.id}`}>
              {product.title}
            </Animated.Text>
          </Pressable>
        </Link>
      ))}
    </View>
  );
}
// app/product/[id].tsx
import { useLocalSearchParams } from 'expo-router';
import Animated from 'react-native-reanimated';
import { View } from 'react-native';

export default function ProductDetail() {
  const { id } = useLocalSearchParams();

  return (
    <View>
      <Animated.Image
        sharedTransitionTag={`product-image-${id}`}
        source={{ uri: 'https://example.com/full.jpg' }}
        style={{ width: '100%', height: 400 }}
      />
      <Animated.Text
        sharedTransitionTag={`product-title-${id}`}
        style={{ fontSize: 32, fontWeight: 'bold', padding: 16 }}
      >
        כותרת מלאה של המוצר
      </Animated.Text>
    </View>
  );
}

הקסם של Reanimated 4: אתם פשוט מציינים אותו sharedTransitionTag בשני המסכים — והספרייה דואגת לכל ה-interpolation אוטומטית. זה אחד מאותם מקרים שאתם מסתכלים על הקוד וחושבים "רגע, זה זה?".

Gestures מתקדמים עם React Native Gesture Handler 3

Reanimated 4 משתלבת באופן מלא עם React Native Gesture Handler 3, ובזכות השילוב הזה אפשר ליצור אינטראקציות מורכבות שלא היו אפשריות בעבר.

Drag & Drop עם snap-back

import { Gesture, GestureDetector, GestureHandlerRootView } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

export default function DraggableCard() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);

  const pan = Gesture.Pan()
    .onUpdate((event) => {
      translateX.value = event.translationX;
      translateY.value = event.translationY;
    })
    .onEnd(() => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
    });

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

  return (
    <GestureHandlerRootView style={{ flex: 1 }}>
      <GestureDetector gesture={pan}>
        <Animated.View
          style={[
            {
              width: 150,
              height: 150,
              backgroundColor: '#8b5cf6',
              borderRadius: 16,
              alignSelf: 'center',
              marginTop: 100,
            },
            animatedStyle,
          ]}
        />
      </GestureDetector>
    </GestureHandlerRootView>
  );
}

אופטימיזציה של ביצועי אנימציה

גם עם Reanimated 4 המהירה, יש כמה כללים חשובים שכדאי לעקוב אחריהם כדי להגיע ל-60 FPS עקביים — או אפילו 120 FPS במכשירים תומכים (כן, ProMotion, אני מסתכל עליך).

1. השתמשו ב-transform במקום ב-layout properties

אנימציות על transform ו-opacity רצות ב-GPU ולא דורשות layout מחדש. הימנעו מאנימציה של width, height, top, left — בכל מקרה שאפשר.

// טוב — רץ ב-GPU
transform: [{ translateX: x.value }, { scale: s.value }]

// פחות טוב — דורש layout
left: x.value, width: w.value

2. שימוש ב-runOnJS רק כשחובה

הפונקציה runOnJS מעבירה קריאה מ-UI Thread ל-JS Thread. זה צוואר בקבוק פוטנציאלי. השתמשו בה רק כשאתם באמת חייבים לעדכן state של React.

import { runOnJS } from 'react-native-reanimated';

const tap = Gesture.Tap().onEnd(() => {
  // רק לעדכון state — לא לכל אינטראקציה
  runOnJS(setIsActive)(true);
});

3. הימנעו מיצירת worklets בכל render

// רע — נוצר מחדש בכל render
const animatedStyle = useAnimatedStyle(() => {
  const computed = expensiveCalculation(); // נוצר מחדש
  return { transform: [{ scale: computed }] };
});

// טוב — שימוש ב-derivedValue
import { useDerivedValue } from 'react-native-reanimated';

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

4. תמיכה ב-Reduced Motion

משתמשים רבים מעדיפים לכבות אנימציות (Accessibility > Reduce Motion ב-iOS). זו לא רק פיצ'ר נחמד — בשביל אנשים עם רגישות תנועה, זה הכרחי. Reanimated 4 תומך בזה אוטומטית, אבל כדאי לוודא:

import { useReducedMotion } from 'react-native-reanimated';

export default function MyComponent() {
  const reduceMotion = useReducedMotion();

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

מדריך מיגרציה מ-Reanimated 3

אם אתם משדרגים מ-Reanimated 3 ל-4, החדשות הטובות הן שרוב הקוד שלכם יעבוד ללא שינוי. אבל יש כמה Breaking Changes שצריך לקחת בחשבון לפני שאתם לוחצים על אנטר ב-terminal.

שינויים מרכזיים

  1. חובה New Architecture: אם אתם עדיין על Bridge הישן, מיגרציה חיונית. הגדירו newArchEnabled: true ב-app.json.
  2. הסרת ה-API הישן: כל הפונקציות מ-Reanimated 1 (כמו Animated.Value הישן) הוסרו לחלוטין. עברו ל-useSharedValue.
  3. שינוי ב-Layout Animations: ה-API נשאר תואם, אבל יש שיפורי ביצועים אוטומטיים.
  4. Shared Transitions: ה-API החדש משתמש ב-sharedTransitionTag במקום ב-SharedTransition class.

צעדי מיגרציה מומלצים

# 1. עדכנו את הגרסה
npm install react-native-reanimated@^4.1.0

# 2. הפעילו New Architecture
# ב-app.json:
{
  "expo": {
    "newArchEnabled": true
  }
}

# 3. ניקוי ובנייה מחדש
npx expo prebuild --clean
cd ios && pod install && cd ..

# 4. הריצו את ה-Codemod (אופציונלי)
npx react-native-reanimated-codemod migrate-to-v4

דוגמה מקצה לקצה: מסך פרופיל אינטראקטיבי

בואו נחבר הכל. נבנה מסך פרופיל עם header שמתכווץ בגלילה, אנימציית כניסה לכל הרכיבים, ו-shared transition לתמונת הפרופיל. זו דוגמה שלקחתי מפרויקט אמיתי — קצת ערכתי אותה לקריאה.

import Animated, {
  useSharedValue,
  useAnimatedScrollHandler,
  useAnimatedStyle,
  interpolate,
  Extrapolation,
  FadeInDown,
} from 'react-native-reanimated';
import { ScrollView, View, Text, Image } from 'react-native';

const HEADER_HEIGHT = 250;
const HEADER_MIN_HEIGHT = 80;

export default function ProfileScreen() {
  const scrollY = useSharedValue(0);

  const scrollHandler = useAnimatedScrollHandler({
    onScroll: (event) => {
      scrollY.value = event.contentOffset.y;
    },
  });

  const headerStyle = useAnimatedStyle(() => {
    const height = interpolate(
      scrollY.value,
      [0, HEADER_HEIGHT - HEADER_MIN_HEIGHT],
      [HEADER_HEIGHT, HEADER_MIN_HEIGHT],
      Extrapolation.CLAMP
    );
    const opacity = interpolate(
      scrollY.value,
      [0, 100],
      [1, 0],
      Extrapolation.CLAMP
    );
    return { height, opacity };
  });

  const avatarStyle = useAnimatedStyle(() => {
    const scale = interpolate(
      scrollY.value,
      [0, HEADER_HEIGHT - HEADER_MIN_HEIGHT],
      [1, 0.5],
      Extrapolation.CLAMP
    );
    return { transform: [{ scale }] };
  });

  return (
    <View style={{ flex: 1 }}>
      <Animated.View
        style={[
          {
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            backgroundColor: '#1e40af',
            zIndex: 10,
            justifyContent: 'center',
            alignItems: 'center',
          },
          headerStyle,
        ]}
      >
        <Animated.Image
          sharedTransitionTag="user-avatar"
          source={{ uri: 'https://example.com/avatar.jpg' }}
          style={[
            { width: 100, height: 100, borderRadius: 50 },
            avatarStyle,
          ]}
        />
      </Animated.View>

      <Animated.ScrollView
        onScroll={scrollHandler}
        scrollEventThrottle={16}
        contentContainerStyle={{ paddingTop: HEADER_HEIGHT + 16 }}
      >
        {[1, 2, 3, 4, 5].map((item, index) => (
          <Animated.View
            key={item}
            entering={FadeInDown.delay(index * 100).springify()}
            style={{
              padding: 20,
              margin: 16,
              backgroundColor: '#f3f4f6',
              borderRadius: 12,
            }}
          >
            <Text style={{ fontSize: 16 }}>פריט מספר {item}</Text>
          </Animated.View>
        ))}
      </Animated.ScrollView>
    </View>
  );
}

שאלות נפוצות (FAQ)

האם Reanimated 4 תואמת אחורה ל-Reanimated 3?

בעיקרון כן — רוב ה-API של Reanimated 3 ממשיך לעבוד ב-Reanimated 4 ללא שינוי. אבל יש דרישה חדשה אחת קריטית: חובה להפעיל את New Architecture (newArchEnabled: true). אם הפרויקט שלכם עדיין על Bridge הישן, צריך לבצע מיגרציה לפני השדרוג. וכן, פיצ'רים שכבר היו deprecated ב-3 הוסרו לחלוטין ב-4.

מתי להשתמש ב-CSS Animations API החדש לעומת ב-Worklets?

הכלל פשוט: השתמשו ב-CSS Animations API לאנימציות פשוטות והצהרתיות (transitions, hover-like effects, keyframes). השתמשו ב-Worklets ו-shared values כשאתם צריכים אינטראקציה עם gestures, חישובים מורכבים, או אנימציות שתלויות ב-state חיצוני. CSS Animations הוא בחירה טובה גם אם אתם בונים קוד שצריך לעבוד גם ב-React Native Web.

איך פותרים בעיה של אנימציה שמתחילה לקפץ (jank)?

סיבות נפוצות (לפי השכיחות שלהן בחיים האמיתיים): (1) אנימציה של layout properties במקום transform — תמיד מעדיפים transform ו-opacity; (2) שימוש מוגזם ב-runOnJS שמעמיס על JS Thread; (3) חישובים יקרים בתוך useAnimatedStyle במקום ב-useDerivedValue; (4) גרפיקה כבדה עם shadow או blur — הפעילו shouldRasterizeIOS או השתמשו ב-renderToHardwareTextureAndroid. כדאי גם להשתמש ב-Performance Monitor של Reanimated 4 לדיבאג.

האם Reanimated 4 עובדת עם React Native Web?

כן, ובאופן הרבה יותר טוב מבעבר. ה-CSS Animations API החדש מתורגם לקוד CSS אמיתי ב-Web, מה שמבטיח ביצועים מעולים. אנימציות מבוססות Worklets עובדות גם הן ב-Web, אבל הן רצות על Main Thread (אין UI Thread נפרד ב-Web), כך שכדאי להעדיף את ה-CSS API למקרים שמתאימים.

מה ההבדל בין Layout Animations של Reanimated לבין LayoutAnimation של React Native Core?

ה-LayoutAnimation של React Native Core מוגבל מאוד — תומך רק ב-3 סוגי אנימציות, לא ניתן להתאמה אישית מתקדמת, ויש בעיות תאימות ב-Android עם New Architecture. Layout Animations של Reanimated 4, לעומת זאת, הם הרבה יותר חזקים: תמיכה ב-springs ו-easings מותאמים, אנימציות entering/exiting נפרדות, אינטגרציה עם FlatList ו-FlashList, ועובדים בצורה זהה ב-iOS, Android ו-Web.

סיכום

React Native Reanimated 4 הוא צעד ענק קדימה עבור עולם האנימציות במובייל. עם תמיכה ב-CSS Animations, Layout Animations משופרות, Shared Element Transitions ושיפורי ביצועים משמעותיים, הספרייה מאפשרת לבנות אפליקציות שמרגישות זריזות, חלקות ומקצועיות — כמו אפליקציות נייטיב אמיתיות.

הצעדים המומלצים ל-2026:

  • שדרגו את הפרויקט שלכם ל-React Native 0.78+ ו-New Architecture
  • התקינו Reanimated 4.1+ והתחילו להשתמש ב-CSS Animations API למקרים פשוטים
  • השתמשו ב-Worklets לאינטראקציות מורכבות עם gestures
  • הוסיפו Shared Element Transitions למסכים מרכזיים באפליקציה
  • בדקו ביצועים עם Performance Monitor ו-DevTools
  • תמיד תמכו ב-Reduced Motion למשתמשים עם רגישות

אם אתם רוצים להעמיק עוד יותר בארכיטקטורה החדשה של React Native (שעליה Reanimated 4 בנויה), קראו את המדריך המלא לארכיטקטורה החדשה של React Native 2026 שלנו, שמסביר את היסודות של JSI, Fabric ו-TurboModules. בהצלחה — ותעשו אנימציות יפות.

אודות הכותב Editorial Team

Our team of expert writers and editors.