Skip to content
Kezdőlap » Stílusok – StyleSheet vagy styled-components?

Stílusok – StyleSheet vagy styled-components?

Ami egy weboldal esetében a CSS, az React Native és React esetében is StyleSheet vagy styled-components. Ez a kettő leggyakoribb módja annak, hogy a képernyő elemekhez „css” stílust rendeljünk.

Nagyon fontos, hogy NEM CSS-ről van szó. Amit „css”-ként adunk meg az valójában JSX. A JSX-ről itt olvashatsz bővebben.

StyleSheet

StyleSheet
Innen van a kép, köszönöm!

A stílusok használatának van egy React Native által biztosított egyszerű és kényelmes módja. Ez a StyleSheet, ami a react-native csomag része:

import { StyleSheet } from "react-native";

Ennek a create metódusával hozunk létre stílus objektumot (általában a fájl legvégén), amiben minden egyes elem egy objektum. És ezeken az objektumokon belül adjuk meg a formázásokat. Például:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginTop: StatusBar.currentHeight,
  },
  searchContainer: {
    padding: 16,
  },
  listContainer: {
    flex: 1,
    backgroundColor: "blue",
    padding: 16,
  },
});

Aztán így rendeljük a komponensekhez, UI elemekhez a stílusokat:

  <SafeAreaView style={styles.container}>
    <View style={styles.searchContainer}>
      <Searchbar />
    </View>
    <View style={styles.listContainer}>
      <RestaurantInfoCard />
    </View>
  </SafeAreaView>

styled-components

styled-components
Innen vettem ezt a „gyönyörű” logót 🙂

Van egy másik kedvelt megoldás is. A styled-components használata. Hasznos linkek:

Telepítés

npm install --save styled-components
vagy
yarn add styled-components

A telepítés során az oldal azt javasolja, hogy az olyan csomagkezelők (pl. Yarn), amik támogatják a package.json fájlban a „resolutions” kulcsot, egy ilyen bejegyzést is célszerű elhelyezni a package.json fájlban:

"resolutions": {
    "styled-components": "^5"
},

Ez megakadályozza az abból fakadó hibákat, ha a projekten belül több más verziójú styled-components csomagot használunk.

Használat

Amit importálunk:

import styled from "styled-components/native";

Példa a használatra:

const Title = styled.Text`
  padding: 16px;
  color: red;
`;

Létrehoztunk egy Title „komponenst”, ami egy react-native Text elemet jelent. A formázást pedig template sztringként adtuk meg. Látható, hogy kell használni a mértékegységet is (különben a konzol hibát fog jelezni), mert ez a háttérben átfordítódik a React Native számára érthető értékké. De ezzel a webfejlesztők is jobban eligazodnak, akik ismerik a CSS-t. Ráadásul a styled megérti a React-ben használt „css” tulajdonságokat és a CSS-ben használtakat is. Tehát például működik a backgroundColor és a background-color is.

Van egy oldal, ahol ki lehet próbálni ezt az átalakítást élőben is, ami valójába a háttérben zajlik:

Korábban a komponenshez rendelt style tulajdonsággal így nézett ki a dolog:

<Text style={styles.title}>{name}</Text>

A styled-components használatával pedig így:

<Title>{name}</Title>

Beszédesebb is a Text helyett használt Title, valamint nem kell megadni a style tulajdonságot sem. Másfelől egy módja annak, hogy igazán CSS szerű stílusokat gyártsunk a React Native-ban.

Konkrét példa

Ez volt StyleSheet stílusokkal egy Card komponens:

<Card elevation={5} style={styles.card}>
    <Card.Cover key={name} source={{ uri: photos[0] }} style={styles.cover} />
    <Text style={styles.title}>{name}</Text>
</Card>

styled-components megoldás. Ez a stílus definíció:

const RestaurantCard = styled(Card)`
  background-color: white;
`;

const RestaurantCardCover = styled(Card.Cover)`
  padding: 20px;
  background-color: white;
`;

const Title = styled.Text`
  padding: 16px;
  color: red;
`;

Ez pedig az alkalmazás:

<RestaurantCard elevation={5}>
   <RestaurantCardCover key={name} source={{ uri: photos[0] }} />
   <Title>{name}</Title>
</RestaurantCard>

Amit meg lehet még figyelni, hogy a színeket most már nem sztringként kell megadni, hanem mint a css-ben:

background-color: white;

Ha egy származtatott értéket akarunk használni, akkor azt pedig ugyanúgy tesszük, ahogy a template sztringeknél mindig. $ és { } használatával:

const SafeArea = styled(SafeAreaView)`
    flex: 1;
    margin-top: ${StatusBar.currentHeight}px;
`;

Hozzáteszem, hogy ha ezt így hagyom, akkor kapok egy hibaüzenetet a konzolban iOS esetén: JSON value ‘px’ of type NSString cannot be converted to a ABI45_0_0YGValue.

Ez azért van, mert a StatusBar-nak a currentHeight tulajdonsága iOS esetén nem értelmezett, ezért null értékkel tér vissza. Ezért a margin-top értéke ez lenne: nullpx. Ezt úgy lehet megoldani, hogy ha a StatusBar.currentHeight nem null, akkor van normális érték. Egyébként pedig legyen 0 az értéke, ami már értelmezhető (0px):

const marginTopValue = StatusBar.currentHeight !== null ? StatusBar.currentHeight : 0;

const SafeArea = styled(SafeAreaView)`
    flex: 1;
    margin-top: ${marginTopValue}px;
`;

Vagy, nem is kell külön változó erre:

const SafeArea = styled(SafeAreaView)`
    flex: 1;
    margin-top: ${StatusBar.currentHeight !== null ? StatusBar.currentHeight : 0}px;
`;

Még másképpen:

const SafeArea = styled(SafeAreaView)<code>
  flex: 1;
  ${StatusBar.currentHeight && <span style="background-color: initial; font-family: inherit; font-size: inherit; color: var(--nv-text-color); font-weight: var(--bodyfontweight); letter-spacing: var(--bodyletterspacing); text-transform: var(--bodytexttransform);">`</span>margin-top: ${StatusBar.currentHeight}px`};
</code>`;

Azt jelenti, hogy ha a StatusBar.currentHeight-nek van értéke, akkor állítsa csak be a margin-top tulajdonságot.

Téma

A styled-components azzal teszi egységessé a stílusokat, hogy lehetővé teszi a témák használatát. Biztosít nekünk egy <ThemeProvider> wrapper komponenst. Ez a komponens ad egy témát az összes olyan React komponensnek, ami a <ThemeProvider>…</ThemeProvider> tag-ek közé kerül. Ezt a context API segítségével teszi. Másképpen megfogalmazva a ThemeProvider olyan, mint egy globális state, rajta keresztül minden olyan React elem hozzáfér a témához, amit a ThemeProvider közrezár.

A téma készítésének egy külön bejegyzést szenteltem.