Heim  >  Artikel  >  Web-Frontend  >  Wie ich das Designsystem für meine React Native-Projekte für eine schnellere Entwicklung einrichte

Wie ich das Designsystem für meine React Native-Projekte für eine schnellere Entwicklung einrichte

Mary-Kate Olsen
Mary-Kate OlsenOriginal
2024-10-06 20:41:021078Durchsuche

Haben Sie jemals Apps erstellt, die Sie selbst nicht verwenden möchten?

Als ich ein Junior-App-Entwickler war, habe ich chaotische Benutzeroberflächen erstellt.

Manchmal dachte ich beim Betrachten dieser Benutzeroberflächen: „Wer in aller Welt würde das überhaupt nutzen wollen? Es sieht schrecklich aus.“

Ein anderes Mal stimmte einfach „etwas nicht“, worauf ich einfach nicht hinweisen konnte.

Während ich früher vom Designteam erstaunlich ausgefeilte Designs bekam, sahen meine Apps nicht einmal 20 % so gut aus.

Ich war mir dieses Problems bewusst und um es zu beheben, habe ich mich auf eine Forschungsreise begeben, bei der ich auf das Konzept eines Designsystems gestoßen bin, das die Art und Weise, wie ich Apps erstelle, verändert hat.

Was ist dieses erstaunliche Ding namens Design System?

Es ist wichtig zu verstehen, was ein Designsystem ist, um zu verstehen, warum wir es brauchen.

Das Designsystem ist im Grunde eine zentralisierte Quelle der Wahrheit für Ihre Designentscheidungen und die Ihres Teams. Hier erfahren Sie, welche Farben Sie wo verwenden sollten. Wie viele Arten von Schaltflächen wird die App haben? Werden die Karten in Ihrer Liste Schatten haben? Alle Antworten stammen aus einem Designsystem.

Hier sind einige der Vorteile eines Designsystems:

  • Konsistente Benutzeroberflächen: Ihre Benutzeroberfläche wird nicht ohne Grund hier und da diese seltsamen Lücken aufweisen. Es wird auf allen Geräten einheitlich aussehen und sich auch so anfühlen.

  • Schnelle Entscheidungen: Designsysteme erzwingen bestimmte Einschränkungen, um Ihre Entscheidungen einfacher und nicht schwieriger zu machen. Je mehr Optionen Sie haben, desto mehr Analyse-Lähmungen treten auf.

  • Skalierbare Apps: Wenn die App wächst, hilft ein Designsystem dabei, Komponenten wiederzuverwenden, anstatt sie von Grund auf neu zu erstellen.

  • Fokus auf Entwicklung: Sie müssen sich nicht mehr darum kümmern, ob der Knopf grün oder blau sein soll. Stattdessen konzentrieren Sie sich auf das Wesentliche.

Tools und Bibliotheken

Obwohl es Unmengen von React Native UI-Bibliotheken gibt, verwende ich einen benutzerdefinierten Ansatz, da ich mit den meisten von ihnen schreckliche Erfahrungen hinsichtlich Leistung und Fehlern gemacht habe.

Die einzige Bibliothek, auf die ich mich für meinen Ansatz verlasse, ist React-Native-Size-Matters.

Bevor Sie jetzt schreien: „Größe spielt keine Rolle!“, möchte ich Ihnen versichern, dass dies der Fall ist. Vor allem, wenn es um mobile Apps geht.

Sie möchten nicht, dass Ihre Benutzer Ihre App öffnen, ein riesiges Logo sehen, das alles bedeckt, und denken: „Was zum Teufel...“, bevor sie löschen, ohne es überhaupt zu versuchen, weil Ihr Logo die Schaltfläche verdeckt hat.

Hier hilft „react-native-size-matters“. Dadurch werden Ihre Apps reaktionsfähig, indem Ihre Komponenten so skaliert werden, dass sie zum Gerät passen. Ganz gleich, welches Gerät der Benutzer besitzt, Ihr Logo bleibt genau dort, wo Sie es platziert haben.

Thema einrichten

Eines der ersten Dinge, die ich definiere, sind meine Kerndesign-Token. Dies sind die Bausteine ​​meines Designsystems. Dazu gehören Farbpaletten, Typografie, Abstände und Schriftgrößen.

Ich mache das, indem ich eine theme.ts-Datei mit dem folgenden Code erstelle:


import {moderateScale} from 'react-native-size-matters';

// after installing custom fonts:
export const FontFamily = {
  bold: 'Poppins-Bold',
  semibold: 'Poppins-SemiBold',
  medium: 'Poppins-Medium',
  regular: 'Poppins-Regular',
  thin: 'Poppins-Thin',
};

const colors = {
  primary100: '#2E2C5F',
  primary80: '#524DA0',
  primary60: '#736DDF',
  primary40: '#A09BFF',
  primary20: '#DCDAFF',

  secondary100: '#484A22',
  secondary80: '#858945',
  secondary60: '#D9DF6D',
  secondary40: '#F8FCA1',
  secondary20: '#FDFFD4',

  neutral100: '#131218',
  neutral90: '#1D1C25',
  neutral80: '#272631',
  neutral70: '#343341',
  neutral60: '#3E3D4D',
  neutral50: '#53526A',
  neutral40: '#757494',
  neutral30: '#9C9AC1',
  neutral20: '#CBC9EF',
  neutral10: '#E8E7FF',
  white: '#fff',
  black: '#222',

  error: '#E7002A',
  success: '#3EC55F',
  warning: '#FECB2F',
  info: '#157EFB',
};

const theme = {
  colors,
  fontSizes: {
    xxl: moderateScale(32),
    xl: moderateScale(28),
    lg: moderateScale(24),
    md: moderateScale(20),
    body: moderateScale(17),
    sm: moderateScale(14),
    xs: moderateScale(12),
    xxs: moderateScale(10),
    xxxs: moderateScale(8),
  },
  spacing: {
    none: 0,
    xxs: moderateScale(4),
    xs: moderateScale(8),
    md: moderateScale(12),
    lg: moderateScale(16),
    xl: moderateScale(20),
    xxl: moderateScale(24),
    xxxl: moderateScale(28),
  },
};

export default theme;


Erstellen wiederverwendbarer Komponenten

Sobald meine Design-Tokens vorhanden sind, definiere ich einige wiederverwendbare Komponenten wie Box, Typografie und Eingabe. Diese Komponenten halten sich an die Design-Tokens und sorgen so für Konsistenz in der gesamten App.

So erstelle ich zum Beispiel eine Box-Komponente:


import {
  View,
  type ViewProps,
  type FlexAlignType,
  type ViewStyle,
} from 'react-native';
import theme from '../styles/theme/theme';

export interface IBox extends ViewProps {
  backgroundColor?: keyof typeof theme.colors;
  p?: keyof typeof theme.spacing;
  pv?: keyof typeof theme.spacing;
  ph?: keyof typeof theme.spacing;
  pt?: keyof typeof theme.spacing;
  pb?: keyof typeof theme.spacing;
  pl?: keyof typeof theme.spacing;
  pr?: keyof typeof theme.spacing;
  m?: keyof typeof theme.spacing;
  mv?: keyof typeof theme.spacing;
  mh?: keyof typeof theme.spacing;
  mt?: keyof typeof theme.spacing;
  mb?: keyof typeof theme.spacing;
  ml?: keyof typeof theme.spacing;
  mr?: keyof typeof theme.spacing;
  gap?: number;
  flex?: number;
  flexDirection?: 'row' | 'column' | 'row-reverse' | 'column-reverse';
  alignItems?: FlexAlignType;
  justifyContent?:
    | 'center'
    | 'flex-start'
    | 'flex-end'
    | 'space-between'
    | 'space-around'
    | 'space-evenly';
  rounded?: boolean;
}

export default function Box({
  backgroundColor,
  p,
  pv,
  ph,
  pt,
  pb,
  pr,
  pl,
  m,
  mv,
  mh,
  mt,
  mb,
  ml,
  mr,
  children,
  style,
  flex,
  alignItems,
  justifyContent,
  flexDirection = 'column',
  rounded = false,
  gap = undefined,
  ...rest
}: IBox) {
  const getMargin = () => {
    const obj: any = {};

    if (m) {
      obj.margin = theme.spacing[m];
      return obj;
    }
    if (mt) obj.marginTop = mt ? theme.spacing[mt] : 0;
    if (mb) obj.marginBottom = mb ? theme.spacing[mb] : 0;
    if (ml) obj.marginLeft = ml ? theme.spacing[ml] : 0;
    if (mr) obj.marginRight = mr ? theme.spacing[mr] : 0;
    if (mv) obj.marginVertical = theme.spacing[mv];
    if (mh) obj.marginHorizontal = theme.spacing[mh];
    return obj;
  };

  const getPadding = () => {
    const obj: any = {};

    if (p) {
      obj.padding = theme.spacing[p];
      return obj;
    }

    if (pt) obj.paddingTop = pt ? theme.spacing[pt] : 0;
    if (pb) obj.paddingBottom = pb ? theme.spacing[pb] : 0;
    if (pl) obj.paddingLeft = pl ? theme.spacing[pl] : 0;
    if (pr) obj.paddingRight = pr ? theme.spacing[pr] : 0;
    if (pv) obj.paddingVertical = theme.spacing[pv];
    if (ph) obj.paddingHorizontal = theme.spacing[ph];

    return obj;
  };

  const boxStyles: ViewStyle[] = [
    {
      backgroundColor: backgroundColor
        ? theme.colors[backgroundColor]
        : undefined,
      flex,
      justifyContent,
      alignItems,
      flexDirection,
      borderRadius: rounded ? 10 : 0,
      gap,
    },
    getMargin(),
    getPadding(),
    style,
  ];

  return (
    <View style={boxStyles} {...rest}>
      {children}
    </View>
  );
}


Ich verwende diese neu erstellte Box-Komponente als Ersatz für View. Es ermöglicht mir, es mithilfe von Requisiten schnell zu gestalten (und Vorschläge zu machen, wenn Sie Typoskript verwenden), etwa so:

How I set up Design System for my React Native Projects for  Faster Development

Hier ist ein Beispiel dafür, wie ich eine Typografiekomponente erstelle, die ich anstelle der Textkomponente von React Native verwende:


import React from 'react';
import {Text, type TextProps} from 'react-native';
import theme, {FontFamily} from '../styles/theme/theme';

export interface ITypography extends TextProps {
  size?: keyof typeof theme.fontSizes;
  color?: keyof typeof theme.colors;
  textAlign?: 'center' | 'auto' | 'left' | 'right' | 'justify';
  variant?: keyof typeof FontFamily;
}

export default function Typography({
  size,
  color,
  textAlign,
  children,
  style,
  variant,
  ...rest
}: ITypography) {
  return (
    <Text
      {...rest}
      style={[
        {
          color: color ? theme.colors[color] : theme.colors.white,
          textAlign,
          fontSize: size ? theme.fontSizes[size] : theme.fontSizes.body,
          fontFamily: variant ? FontFamily[variant] : FontFamily.regular,
        },
        style,
      ]}>
      {children}
    </Text>
  );
}


Hier ist eine Vorschau, wie schnell ich meiner benutzerdefinierten Typografie-Komponente Stile hinzufügen kann:

How I set up Design System for my React Native Projects for  Faster Development

Benutzerdefinierter UseTheme-Hook

Anstatt das Theme immer wieder zu importieren, mache ich meinen Code besser lesbar, indem ich einen benutzerdefinierten useTheme-Hook erstelle, den ich an einer beliebigen Stelle in der App aufrufe, um Stile hinzuzufügen, die zu meinem Theme passen.

Dazu nutze ich die Kontext-API von React, um mein Thema in der App zu übergeben.

Ich erstelle eine ThemeProvider.tsx-Datei und definiere darin ThemeContext und ThemeProvider, um meine App-Komponente darin einzubinden. Hier ist der Code:


import React, {type PropsWithChildren, createContext} from 'react';
import theme from './theme';

export const ThemeContext = createContext(theme);

export default function ThemeProvider({children}: PropsWithChildren) {
  return (
    <ThemeContext.Provider value={theme}>{children}</ThemeContext.Provider>
  );
}


Dann in meiner App-Komponente:


export default function App() {
  return (
    <ThemeProvider>
      <AppNavigation />
    </ThemeProvider>
  );
}


Da meine gesamte App nun Zugriff auf ThemeContext hat, erstelle ich meinen useTheme-Hook:


import {useContext} from 'react';
import {ThemeContext} from '../styles/theme/ThemeProvider';

export default function useTheme() {
  const theme = useContext(ThemeContext);
  return theme;
}


Jetzt kann ich überall auf mein Theme zugreifen, indem ich den useTheme-Hook wie folgt aufrufe:


const theme = useTheme();
// example usage:
theme.colors.primary100;
theme.spacing.md;
theme.fontSizes.lg;


Dunkler Modus

Um den Dunkelmodus zu implementieren, füge ich in der theme.ts-Datei eine weitere Farbpalette hinzu, die die Farben für den Dunkelmodus enthält.


export const darkTheme = {
  // define dark mode colors here keeping the keys same as the light mode only changing the values.
}


Then, in ThemeProvider, I simply check user settings and switch the theme like so:


<p>import {useColorScheme} from 'react-native';</p>

<p>export default function ThemeProvider({children}: PropsWithChildren) {<br>
const isDarkMode = useColorScheme() === 'dark';<br>
  return (<br>
    <ThemeContext.Provider value={isDarkMode ? darkTheme : theme}>{children}</ThemeContext.Provider><br>
  );<br>
}</p>




Conclusion

Following this clear structured approach has brought much needed clarity, consistency, and aesthetics in my app while also sped up my development speed by at least 10x since I no longer have to dwell over design decisions.

I encourage you to try this approach and let me know what you guys think in the comments. Maybe improve it a little bit eh?

Das obige ist der detaillierte Inhalt vonWie ich das Designsystem für meine React Native-Projekte für eine schnellere Entwicklung einrichte. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn