ホームページ > ウェブフロントエンド > jsチュートリアル > @shopify/restyle を使用して React Native で型強制 UI コンポーネントを構築する方法

@shopify/restyle を使用して React Native で型強制 UI コンポーネントを構築する方法

Mary-Kate Olsen
リリース: 2024-12-02 09:05:15
オリジナル
183 人が閲覧しました

ブログに技術的な記事を書いてからかなりの時間が経ちましたが、ここでは @shopify/restyle と expo を使用して React Native で型強制 UI コンポーネントを構築することに関する新しい記事を紹介します。

@shopify/restyle は、UI コンポーネントにタイプ セーフティと一貫性をもたらす React Native 用の強力なスタイル ライブラリです。従来のスタイル設定アプローチとは異なり、Restyle を使用すると、アプリケーション全体にデザイン システムの原則を適用する一元化されたテーマ構成を作成できます。

はじめる

プロジェクトのセットアップ

  • expo を使用して反応ネイティブ プロジェクトをセットアップする
npx create-expo-app@latest
ログイン後にコピー
ログイン後にコピー
  • プロジェクト ディレクトリに移動し、expo を使用して @shopify/restyle パッケージをインストールします。
cd /path/to/project
npx expo install @shopify/restyle
ログイン後にコピー

テーマの作成

デザイン システムを定義するための theme.tsx ファイルを作成します。

touch theme.tsx
ログイン後にコピー
  • デフォルトのテーマ設定をコピーして貼り付けます
import {createTheme} from '@shopify/restyle';

const palette = {
  purpleLight: '#8C6FF7',
  purplePrimary: '#5A31F4',
  purpleDark: '#3F22AB',

  greenLight: '#56DCBA',
  greenPrimary: '#0ECD9D',
  greenDark: '#0A906E',

  black: '#0B0B0B',
  white: '#F0F2F3',
};

const theme = createTheme({
  colors: {
    mainBackground: palette.white,
    cardPrimaryBackground: palette.purplePrimary,
  },
  spacing: {
    s: 8,
    m: 16,
    l: 24,
    xl: 40,
  },
  textVariants: {
    header: {
      fontWeight: 'bold',
      fontSize: 34,
    },
    body: {
      fontSize: 16,
      lineHeight: 24,
    },
    defaults: {
      // We can define a default text variant here.
    },
  },
});

export type Theme = typeof theme;
export default theme;
ログイン後にコピー

テーマプロバイダーの実装

app/_layout.tsx を更新します:

import { DarkTheme, DefaultTheme } from "@react-navigation/native";
import { useFonts } from "expo-font";
import { Stack } from "expo-router";
import * as SplashScreen from "expo-splash-screen";
import { StatusBar } from "expo-status-bar";
import { useEffect } from "react";
import "react-native-reanimated";

import { ThemeProvider } from "@shopify/restyle";
import theme from "@/theme";

// Prevent the splash screen from auto-hiding before asset loading is complete.
SplashScreen.preventAutoHideAsync();

export default function RootLayout() {
  const [loaded] = useFonts({
    SpaceMono: require("../assets/fonts/SpaceMono-Regular.ttf"),
  });

  useEffect(() => {
    if (loaded) {
      SplashScreen.hideAsync();
    }
  }, [loaded]);

  if (!loaded) {
    return null;
  }

  return (
    <ThemeProvider theme={theme}>
      <Stack>
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        <Stack.Screen name="+not-found" />
      </Stack>
      <StatusBar>



<h2>
  
  
  Creating Reusable Components
</h2>

<h3>
  
  
  Text Component
</h3>



<pre class="brush:php;toolbar:false">touch components/Text.tsx
ログイン後にコピー
// In components/Text.tsx

import {createText} from '@shopify/restyle';
import {Theme} from '../theme';

export const Text = createText<Theme>();

ログイン後にコピー

ホーム画面に使ってみましょう

import { Text } from "@/components/Text";
import { SafeAreaView } from "react-native-safe-area-context";

export default function HomeScreen() {
  return (
    <SafeAreaView>
      <Text margin="m" variant="header">
        This is the Home screen. Built using @shopify/restyle.
      </Text>
    </SafeAreaView>
  );
}

ログイン後にコピー

上記のコードでわかるように、マージンを数値ではなく「m」として渡しています。値は、theme.tsxfile から取得しています。

// ./theme.tsx

const theme = createTheme({
  spacing: {
    s: 8,
    m: 16, // margin="m"
    l: 24,
    xl: 40,
  },
  textVariants: {
    header: { // our text header variant
      fontWeight: 'bold',
      fontSize: 34,
    },
    body: {
      fontSize: 16,
      lineHeight: 24,
    },
  },
    // ...rest of code
  },
});
ログイン後にコピー

ホームページのビューは次のようになります

How to build type-enforced UI components in React Native using @shopify/restyle

スケルトンローダーコンポーネント

スケルトン ローダー カードを作成しましょう

touch components/SkeletonLoader.tsx
ログイン後にコピー
// components/SkeletonLoader.tsx

import {
  BackgroundColorProps,
  createBox,
  createRestyleComponent,
  createVariant,
  spacing,
  SpacingProps,
  VariantProps,
} from "@shopify/restyle";
import { Theme } from "@/theme";
import { View } from "react-native";

const Box = createBox<Theme>();

type Props = SpacingProps<Theme> &
  VariantProps<Theme, "cardVariants"> &
  BackgroundColorProps<Theme> &
  React.ComponentProps<typeof View>;

const CardSkeleton = createRestyleComponent<Props, Theme>([
  spacing,
  createVariant({ themeKey: "cardVariants" }),
]);

const SkeletonLoader = () => {
  return (
    <CardSkeleton variant="elevated">
      <Box
        backgroundColor="cardPrimaryBackground"
        height={20}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      >
      </Box>

      <Box
        backgroundColor="cardPrimaryBackground"
        height={100}
        marginBottom="s"
        width="90%"
        overflow="hidden"
        borderRadius={"m"}
      >
      </Box>
      <Box
        backgroundColor="cardPrimaryBackground"
        height={50}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      >
      </Box>
    </CardSkeleton>
  );
};

export default SkeletonLoader;

ログイン後にコピー
  • @shopify/restyle パッケージから定義済みコンポーネントとして新しいボックスを作成します。これがスケルトン ボックスの作成方法になります。
const Box = createBox<Theme>();
ログイン後にコピー
  • createStyleComponent を使用して新しい CardSkeleton コンポーネントを作成し、カスタム コンポーネントを作成します。また、theme.tsx ファイルで定義する必要があるスペーシングと CardVariants である props を渡しました。
type Props = SpacingProps<Theme> &
  VariantProps<Theme, "cardVariants"> &
  BackgroundColorProps<Theme> &
  React.ComponentProps<typeof View>;

const CardSkeleton = createRestyleComponent<Props, Theme>([
  spacing,
  createVariant({ themeKey: "cardVariants" }),
]);
ログイン後にコピー
  • SkeletonLoader コンポーネントを作成して、Skelton Card コンポーネントをレンダリングします。
// components/SkeletonLoader.tsx

export const SkeletonLoader = () => {
  return (
    <CardSkeleton variant="elevated">
      <Box
        backgroundColor="cardPrimaryBackground"
        height={20}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      ></Box>

      <Box
        backgroundColor="cardPrimaryBackground"
        height={100}
        marginBottom="s"
        width="90%"
        overflow="hidden"
        borderRadius={"m"}
      ></Box>
      <Box
        backgroundColor="cardPrimaryBackground"
        height={50}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      ></Box>
    </CardSkeleton>
  );
};

ログイン後にコピー

これを機能させるために残っていることは 1 つあります。theme.tsx ファイルを更新して CardVariants を含めます

const theme = createTheme({
  colors: {
    // Add Black Color to use it later on
    black: palette.black,
  },
  // Add Border Radius Variants
  borderRadii: {
    s: 4,
    m: 10,
    l: 25,
    xl: 75,
  },
  // Add Card Variants
  cardVariants: {
    elevated: {
      shadowColor: "black",
      shadowOffset: { width: 0, height: 2 },
      shadowOpacity: 0.1,
      shadowRadius: 4,
      elevation: 3,
      borderRadius: "m",
    },
    defaults: {
      padding: "m",
      borderRadius: "m",
    },
  },
});

ログイン後にコピー

それは素晴らしいですが、コンポーネントにアニメーションを付けてみましょう

// components/SkeletonLoader.tsx

const ShimmerAnimation = () => {
  const shimmerTranslate = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.loop(
      Animated.timing(shimmerTranslate, {
        toValue: 1,
        duration: 1500,
        useNativeDriver: true,
      })
    ).start();
  }, [shimmerTranslate]);

  const translateX = shimmerTranslate.interpolate({
    inputRange: [0, 1],
    outputRange: [-300, 300],
  });

  return (
    <Animated.View
     >



<p>and let’s use it in our Skeleton Loader Component<br>
</p>

<pre class="brush:php;toolbar:false">// components/SkeletonLoader.tsx

export const SkeletonLoader = () => {
  return (
    <CardSkeleton variant="elevated">
      <Box
        backgroundColor="cardPrimaryBackground"
        height={20}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      >
        <ShimmerAnimation />
      </Box>

      <Box
        backgroundColor="cardPrimaryBackground"
        height={100}
        marginBottom="s"
        width="90%"
        overflow="hidden"
        borderRadius={"m"}
      >
        <ShimmerAnimation />
      </Box>
      <Box
        backgroundColor="cardPrimaryBackground"
        height={50}
        marginBottom="s"
        width="70%"
        overflow="hidden"
        borderRadius={"m"}
      >
        <ShimmerAnimation />
      </Box>
    </CardSkeleton>
  );
};

ログイン後にコピー

完全なコンポーネント コードは次のとおりです。

// components/SkeletonLoader.tsx

import { useEffect, useRef } from "react";
import { Animated } from "react-native";
import {
  BackgroundColorProps,
  createBox,
  createRestyleComponent,
  createVariant,
  spacing,
  SpacingProps,
  VariantProps,
} from "@shopify/restyle";
import { Theme } from "@/theme";
import { View } from "react-native";

const Box = createBox<Theme>();

const ShimmerAnimation = () => {
  const shimmerTranslate = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.loop(
      Animated.timing(shimmerTranslate, {
        toValue: 1,
        duration: 1500,
        useNativeDriver: true,
      })
    ).start();
  }, [shimmerTranslate]);

  const translateX = shimmerTranslate.interpolate({
    inputRange: [0, 1],
    outputRange: [-300, 300],
  });

  return (
    



Et voila, we made a skeleton loader card using @shopify/restyle using

How to build type-enforced UI components in React Native using @shopify/restyle

Support for dark mode

Let’s start with adding dark theme configuration, in your theme.tsxfile

// theme.tsx

export const darkTheme: Theme = {
  ...theme,
  colors: {
    ...theme.colors,
    mainBackground: palette.white,
    cardPrimaryBackground: palette.purpleDark,
    greenPrimary: palette.purpleLight,
  },
  textVariants: {
    ...theme.textVariants,
    defaults: {
      ...theme.textVariants.header,
      color: palette.purpleDark,
    },
  },
ログイン後にコピー

layout.tsx ファイルにダークテーマの設定を追加して、アプリのレイアウトにダークテーマの設定を追加します

npx create-expo-app@latest
ログイン後にコピー
ログイン後にコピー
  • カラー スキーマに基づいて、デフォルトのライト テーマを使用するか、ダーク モードでは、theme.tsx ファイルで定義されている darkTheme 構成を使用します。
 // app/_layout.tsx

 テーマ、{ darkTheme } を "@/theme" からインポートします。

 //... 残りのコード

    <ThemeProvider テーマ={colorSchema === "ダーク" ? darkTheme : テーマ}>
      
        <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
        <Stack.Screen name=" 見つかりません" />
      </スタック>
      



<p>これがダークモードとライトモードです。</p>

<p><img src="https://img.php.cn/upload/article/000/000/000/173310152340178.jpg" alt="How to build type-enforced UI components in React Native using @shopify/restyle"></p>

<p><img src="https://img.php.cn/upload/article/000/000/000/173310152557660.jpg" alt="How to build type-enforced UI components in React Native using @shopify/restyle"></p>

<p>ほら、@shopify/restyle パッケージを使用してタイプ強制 UI コンポーネントを作成できました</p>

<p>ありがとうございます:)</p>


          

            
        
ログイン後にコピー

以上が@shopify/restyle を使用して React Native で型強制 UI コンポーネントを構築する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート