react-native-reanimated-skeleton

repository·main·Indexed 40 days ago

https://github.com/marcuzgabriel/react-native-reanimated-skeleton

A customizable skeleton loading component for React Native and Web, built using react-native-reanimated v3. Version 1.6.0 supports automatic layout based on children or manual custom layouts via the layout prop. Features include configurable animation types (none, shiver, pulse), animation directions, and customizable bone and highlight colors.

Tokens
4K
Snippets
12
Records
16
Agent score
99%

What's inside react-native-reanimated-skeleton

  1. How to use Skeleton with Custom Layout

    main

    In Custom Layout mode, you provide a layout prop to the Skeleton component. This prop is an array of objects where each object specifies the dimensions and styling for a specific bone. It is highly recommended to provide a unique key for each object in the layout array. This mode is useful when you want the skeleton to look different from the actual content being loaded.

    import Skeleton from "react-native-reanimated-skeleton";
    
    export default function Placeholder() {
      return (
        <Skeleton
          containerStyle={{ flex: 1, width: 300 }}
          isLoading={false}
          layout=[
            { key: "someId", width: 220, height: 20, marginBottom: 6 },
            { key: "someOtherId", width: 180, height: 20, marginBottom: 6 },
          ]
        >
          <Text style={styles.normalText}>Your content</Text>
          <Text style={styles.bigText}>Other content</Text>
        </Skeleton>
      );
    }
  2. How to use Skeleton with Child Layout

    main

    In Child Layout mode, the Skeleton component automatically determines the dimensions and positions of the skeleton bones based on the dimensions of its direct children. You simply wrap your content inside the Skeleton component and toggle the isLoading prop.

    import Skeleton from "react-native-reanimated-skeleton";
    
    <Skeleton isLoading={true} containerStyle={styles.container}>
      <Text style={styles.normalText}>Your content</Text>
      <Text style={styles.bigText}>Other content</Text>
    </Skeleton>
  3. Install in Expo projects

    main

    Because react-native-linear-gradient is not supported in Expo, you must use a postinstall script to transform the library's imports to use expo-linear-gradient.

    1. Obtain the required script from the official repository scripts folder.
    2. Add the postinstall script to your package.json.
    3. Run npm install and restart your app.

    The script performs the following transformation: import LinearGradient from 'react-native-linear-gradient'; $\rightarrow$ import { LinearGradient } from 'expo-linear-gradient';

  4. Configure ESLint for the project

    main

    The project uses a flat configuration file (eslint.config.mjs) based on typescript-eslint. It integrates several plugins including React, React Native, Jest, Prettier, and the React Compiler.

    Key configuration features include:

    • TypeScript Support: Uses recommendedTypeChecked, strict, and stylistic configurations.
    • React Native: Uses eslint-plugin-react-native (wrapped with fixupPluginRules for ESLint 9 compatibility).
    • React Hooks: Enforces rules-of-hooks and exhaustive-deps.
    • Prettier: Integrated via eslint-plugin-prettier to treat formatting issues as ESLint errors.
    • React Compiler: Includes the react-compiler/react-compiler rule set to an error level.
  5. Configure Metro for the @rnrs/app package

    main

    The Metro configuration for the @rnrs/app package uses @rnx-kit/metro-config to define transformation options. Specifically, it disables experimentalImportSupport and inlineRequires within the getTransformOptions transformer setting. This configuration is used to manage how files are transformed during the bundling process in the React Native environment.

    const { makeMetroConfig } = require('@rnx-kit/metro-config');
    
    module.exports = makeMetroConfig({
      transformer: {
        getTransformOptions: async () => ({
          transform: {
            experimentalImportSupport: false,
            inlineRequires: false,
          },
        }),
      },
    });
  6. Skeleton component props

    main

    The Skeleton component accepts the following props to control its appearance and animation behavior:

    | Name | Type | Default | Description |
    | ------------------ | ---------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------- |
    | isLoading | bool | **required** | Shows the Skeleton bones when true |
    | layout | array of objects | [] | A custom layout for the Skeleton bones |
    | duration | number | 1200 ms | Duration of one cycle of animation |
    | containerStyle | object | flex: 1 | The style applied to the View containing the bones |
    | easing | Easing | bezier(0.5, 0, 0.25, 1) | Easing of the bones animation |
    | animationType | string | "shiver" | The animation to be used for animating the bones |
    | animationDirection | string | "horizontalLeft" | Used only for shiver animation, describes the direction and end-point (ex: horizontalLeft goes on the x-axis from right to left) |
    | boneColor | string | "#E1E9EE" | Color of the bones |
    | highlightColor | string | "#F2F8FC" | Color of the highlight of the bones |
  7. Use the Skeleton component

    main

    The Skeleton component renders a placeholder layout (bones) while content is loading. When isLoading is true, it displays animated shapes based on the provided layout prop. When isLoading is false, it renders the children component. If hasFadeIn is enabled, the children will fade in smoothly using a 250ms duration.

    import Skeleton from 'react-native-reanimated-skeleton';
    
    <Skeleton
      isLoading={loading}
      layout={[
        { width: 100, height: 20, borderRadius: 4 },
        { width: 200, height: 100, borderRadius: 8 }
      ]}
      hasFadeIn={true}
    >
      <MyActualContent />
    </Skeleton>
  8. Configure Skeleton component via ISkeletonProps

    main

    The ISkeletonProps interface defines the configuration options for the Skeleton component. You can control the loading state, the layout of the skeleton bones, animation styles, and colors.

    Key props include:

    • isLoading: Boolean determining if the skeleton is active.
    • layout: An array of ICustomViewStyle objects defining the shape and position of the skeleton bones.
    • animationType: Choose between 'none', 'shiver', or 'pulse'.
    • animationDirection: Controls the movement direction (e.g., 'horizontalLeft', 'verticalTop', 'diagonalDownRight').
    • boneColor: The base color of the skeleton.
    • highlightColor: The color of the moving highlight animation.
    • duration: The animation duration in milliseconds.
    • containerStyle: Styles for the outer container.
    • hasFadeIn: Boolean to enable/disable fade-in effect.
    <Skeleton
      isLoading={true}
      layout={[
        { width: 100, height: 20, borderRadius: 4 },
        { width: 200, height: 100, borderRadius: 8 }
      ]}
      animationType="shiver"
      animationDirection="horizontalLeft"
      boneColor="#E1E9EE"
      highlightColor="#F2F8FC"
    />
  9. Reference: ESLint rules and settings

    main

    The following rules and settings are explicitly defined in the project's ESLint configuration. Note that many @typescript-eslint rules are currently disabled (0) to accommodate existing patterns in the codebase.

    // Core Rules
    {
      rules: {
        'prettier/prettier': 'error',
        'react-hooks/rules-of-hooks': 'error',
        'react-hooks/exhaustive-deps': 'warn',
        'react-native/no-inline-styles': 'warn',
        'react-native/sort-styles': 'off',
        'react-native/no-color-literals': 'off',
        'import/no-cycle': ['error', { maxDepth: 1, ignoreExternal: true }],
        'no-console': 2,
        'dot-notation': ['error', { "allowKeywords": false }],
        'react-compiler/react-compiler': 'error'
      }
    }
    
    // Settings
    {
      settings: {
        react: { pragma: 'React', version: 'detect' },
        jest: { pragma: 'jest', version: 'detect' },
        'import/resolver': {
          typescript: {
            alwaysTryTypes: true,
            project: './tsconfig.json',
          },
        },
        'import/ignore': ['react-native'],
        'import/extensions': ['.js', '.jsx', '.ts', '.tsx', '.d.ts'],
      }
    }
    
    // Jest Specific Rules
    {
      rules: {
        'jest/no-mocks-import': 'off',
        'jest/no-conditional-expect': 'off',
        'jest/expect-expect': 'off',
        'jest/prefer-expect-assertions': 'off'
      }
    }
  10. Configure SkeletonProps

    main

    The Skeleton component accepts the following props via the ISkeletonProps interface:

    PropTypeDefaultDescription
    containerStyleViewStylestyles.containerStyle for the outer container.
    durationnumberDEFAULT_CONFIG.DURATIONDuration of the animation cycle.
    easingEasingFunctionDEFAULT_CONFIG.EASINGEasing function for the animation.
    layoutArray<any>[]Array defining the shapes (bones) to render during loading.
    animationTypestringDEFAULT_CONFIG.ANIMATION_TYPEType of animation (e.g., 'shiver').
    animationDirectionstringDEFAULT_CONFIG.ANIMATION_DIRECTIONDirection of the animation.
    isLoadingbooleanDEFAULT_CONFIG.LOADINGDetermines if the skeleton or the children are visible.
    boneColorColorValueDEFAULT_CONFIG.BONE_COLORColor of the skeleton bones.
    highlightColorColorValueDEFAULT_CONFIG.HIGHLIGHT_COLORColor of the highlight animation.
    hasFadeInbooleanundefinedIf true, children will fade in when isLoading becomes false.
    childrenReactNodeundefinedThe actual content to display once loading is complete.