Home > Mobile >  React Native parent component to screens
React Native parent component to screens

Time:07-22

I would like to have a parent component wrapping the screens so I can pass global styles to those components like instead of repeating same global styles in each component. However, Navigator doesn't accept View or anything with styles inside it.

return (
    <NavigationContainer>
      <Navigator>
        {isAuthenticated ? (
          <>
            <Screen options={{headerShown: false}} name={'TabsNavigation'} component={BottomTabsNavigator}/>
            <Screen options={{headerShown: false}} name={'Home'} component={Home}/>
          </>
        ) : (
          <>
            <Screen options={{headerShown: false}} name={'Login'} component={Login}/>
            <Screen options={{headerShown: false}} name={'Register'} component={Register}/>
          </>
        )}
      </Navigator>
    </NavigationContainer>
  );

How can I achieve this?

EDIT

All my components start like this:

<SafeAreaView style={styles(theme).flex}>
    <ScrollView contentInsetAdjustmentBehavior="automatic">
        <View>
            <Text>Content here</Text>
        </View>
    </ScrollView>
</SafeAreaView>

So instead I want to make it so all my components start like this:

<View>
    <Text>Content here</Text>
</View>

I want to move SafeAreaView and ScrollView to a parent component

CodePudding user response:

After the edit it's much more clear, thanks! And the answer is very different so I made a new one.

What you want is called an HOC, for Higher-Order Component. React makes this easy with the children prop. Here's an example based on your code:

const ScreenWrapper = ({ children, theme }) => {
  return (
    <SafeAreaView style={styles(theme).flex}>
      <ScrollView contentInsetAdjustmentBehavior="automatic">
        {children}
      </ScrollView>
    </SafeAreaView>
  );
};

You'd use this in your screens like this:

  <ScreenWrapper>
    <View>
      <Text>Content here</Text>
    </View>
  </ScreenWrapper>

Anything between <ScreenWrapper> and </ScreenWrapper> is passed to the component under the children prop. This pattern should make it easy to achive what you want. This is how most of the React built-in components (like View or Text) work.

You can read more about this here: https://reactjs.org/docs/jsx-in-depth.html#children-in-jsx

CodePudding user response:

NB: After the edit, this answer does not fit the question


It's not 100% clear to me what you're trying to achieve, however, there are many ways to go about using a shared theme.

  • React Navigation has built-in theming for its components, using the theme prop. You can read about how to use the theme prop here: https://reactnavigation.org/docs/themes/

  • You can save and export one or several StyleSheets, and import them wherever you want. Example:

export const colors = {
  blue: '#02B4F3',
};

export const textStyles = StyleSheet.create({
  header: {
    fontSize: 24,
    color: colors.blue,
  },
  ...
});

// etc
// and then in your component

import { textStyles } from 'styles';

...
  <Text style={textStyles.header}>Header</Text>
...
  • You can make functions that return StyleSheets based on the theme. Example:
export const textStyles = (theme) => StyleSheet.create({
  header: {
    fontSize: 24,
    color: theme === 'light' ? colors.blue : colors.yellow,
  },
});
  • You can use React Context to hold your themes. There are lots of tutorials for this, like this one (which I haven't tried btw): https://betterprogramming.pub/react-context-api-part-1-dark-theme-3f00666cbacb

  • Using a UI library like react-native-paper or Native Base often includes support for theming, although I wouldn't encourage using one only for theming, and in general I do not prefer working with these libraries.

  • Related