Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Build Themed Components in React Native
Spencer Carli
Spencer Carli

Posted on • Originally published atreactnativeschool.com

     

Build Themed Components in React Native

Building a multi-theme app doesn't have to be complicated, so long as you take advantage of custom components. In this tutorial we'll cover how to create your own versions of core React Native components that are automatically themed to use the right colors based on the user's preferred color scheme.

Take a look at the code for theStopWatch screen below. There's nothing unique to supporting multiple themes in it, but it fully supports multiple themes thanks to the custom components we'll create.

// screens/StopWatch.tsximport{StyleSheet}from"react-native"import{Text,View,StatusBar,SafeAreaView}from"components/themed"import{CircleButton}from"components/buttons"import{useStopWatch}from"hooks/useStopWatch"import{LapList}from"components/lists"constStopWatch=()=>{const{time,isRunning,start,stop,reset,lap,laps,currentLapTime,hasStarted,slowestLapTime,fastestLapTime,}=useStopWatch()return(<SafeAreaViewstyle={{flex:1}}><StatusBar/><Viewstyle={styles.container}><Textstyle={styles.timeText}>{time}</Text><Viewstyle={styles.row}><CircleButtononPress={()=>{isRunning?lap():reset()}}>{isRunning?"Lap":"Reset"}</CircleButton><CircleButtononPress={()=>{isRunning?stop():start()}}color={isRunning?"red":"green"}>{isRunning?"Stop":"Start"}</CircleButton></View><LapListhasStarted={hasStarted}currentLapTime={currentLapTime}laps={laps}fastestLapTime={fastestLapTime}slowestLapTime={slowestLapTime}/></View></SafeAreaView>)}conststyles=StyleSheet.create({container:{flex:1,alignItems:"center"},timeText:{fontSize:60,fontWeight:"300",marginTop:100,fontVariant:["tabular-nums"],// fixed width character},row:{flexDirection:"row",width:"100%",justifyContent:"space-between",paddingHorizontal:20,marginTop:100,},})exportdefaultStopWatch
Enter fullscreen modeExit fullscreen mode

Example of light and dark theme

The useThemeColors Hook

At the core of our themed components is theuseThemeColors hook. This hook does the heavy lifting for our theme based logic.

We built a version of this hook ina recent tutorial. I would recommend you read it to get a better understanding of how to implement it and the "why" behind it.

From this hook we return an object with two pieces of data in it:

  1. The colors for the currently active theme. This is standardized between "light" and "dark". It could also expand to other themes as well.
  2. isDark will be used to determine the color of things like theStatusBar. We can't change the actual text color but we can determine if the text should be light or dark.
// hooks/useThemeColors.tsximportColorsfrom"constants/Colors"import{useColorScheme}from"hooks/useColorScheme"exportfunctionuseThemeColors(){consttheme=useColorScheme()return{isDark:theme==="dark",colors:Colors[theme],}}
Enter fullscreen modeExit fullscreen mode

The View Components

The goal of our customView component is to serve as a building block that functions just like a normalView. All we do is set the background color and then forward any user defined props onto the underlyingView.

This allows us to use the customView just like a normalView, including overriding our default background color. The same goes for theSafeAreaView.

// components/themed/View.tsximport{ViewasDefaultView,ViewProps}from"react-native"import{SafeAreaViewasDefaultSafeAreaView}from"react-native-safe-area-context"import{useThemeColors}from"hooks/useThemeColors"exportfunctionView(props:ViewProps){const{style,...otherProps}=propsconst{colors}=useThemeColors()return(<DefaultViewstyle={[{backgroundColor:colors.background},style]}{...otherProps}/>)}exportconstSafeAreaView=(props:ViewProps)=>{const{style,...otherProps}=propsconst{colors}=useThemeColors()return(<DefaultSafeAreaViewstyle={[{backgroundColor:colors.background},style]}{...otherProps}/>)}
Enter fullscreen modeExit fullscreen mode

Learn how to set up path alias' like you see used throughout this post

The Text Component

Just like theView component all theText component does is set the text color based on the theme. Other options could be to set a default font family, add different text types ("title", "subtitle", etc). Even if you're not supporting multiple themes creating your ownText component is a great practice so you don't need to update styles all over your app when a font family changes.

// components/themed/Text.tsximport{TextasDefaultText,TextProps}from"react-native"import{useThemeColors}from"hooks/useThemeColors"exportconstText=(props:TextProps)=>{const{style,...otherProps}=propsconst{colors}=useThemeColors()return<DefaultTextstyle={[{color:colors.text},style]}{...otherProps}/>}
Enter fullscreen modeExit fullscreen mode

The StatusBar Component

This one is unique because we can only customize parts of it. Therefore we use theisDark data to determine whether we should use the light text or dark text. We can also set the background color of the StatusBar on Android.

The benefit of using this approach is that if we choose to add more themes (asthe example repo this tutorial is based on has) we can define if a theme is light or dark in one place.

// components/themed/StatusBar.tsximport{StatusBarasDefaultStatusBar,StatusBarProps}from"react-native"import{useThemeColors}from"hooks/useThemeColors"exportconstStatusBar=(props:StatusBarProps)=>{const{isDark,colors}=useThemeColors()constbarStyle=isDark?"light-content":"dark-content"return(<DefaultStatusBarbarStyle={barStyle}backgroundColor={colors.background}{...props}/>)}
Enter fullscreen modeExit fullscreen mode

CHALLENGE

There are more default UI elements you can theme. With what's been discussed here, how would you do it?

  • The different buttons. Notice they have a prop ofcolor but that color stated may not be the same for each theme.
  • The tab bar from React Navigation. The background color and the icons are customized based on the theme.

Theanswers exist in the repo but I'd encourage you to think about how you'd do it before digging into the repo to find how I did it.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Student. Teacher. Firefighter. Pizza fiend. I teach others while teaching myself, typically with React Native.
  • Location
    Nashville, TN
  • Work
    Developer/Teacher
  • Joined

More fromSpencer Carli

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp