DailyDevDiet

logo - dailydevdiet

Learn. Build. Innovate. Elevate your coding skills with dailydevdiet!

Chapter 5: React Native Components and Core Components

React Native Components

Introduction

React Native is built around the concept of components, which are the building blocks of your mobile application’s user interface. Understanding React Native components is fundamental to becoming proficient in React Native development. In this chapter, we’ll explore what components are, how they work, and dive into the core components provided by React Native.

What Are React Native Components?

Components in React Native are independent, reusable pieces of code that return elements describing what should appear on the screen. They serve as the foundation for building user interfaces in React Native applications.

Types of Components in React Native

There are two primary types of components in React Native:

  1. Class Components: Traditional component type that uses ES6 classes.
  2. Functional Components: Modern approach that uses JavaScript functions and React Hooks.

Class Component Example:

import React, { Component } from 'react';
import { Text, View } from 'react-native';

class HelloWorld extends Component {

  render() {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>Hello, World!</Text>
      </View>
    );
  }
}

export default HelloWorld;

Functional Component Example:

import React from 'react';
import { Text, View } from 'react-native';

const HelloWorld = () => {
  return (
    <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
      <Text>Hello, World!</Text>
    </View>
  );
};

export default HelloWorld;

Core Components in React Native

React Native provides a set of essential, built-in components that map directly to native UI elements on both iOS and Android platforms. These are known as core components.

View

View is the most fundamental component for building a UI. It’s a container that supports layout with flexbox, style, touch handling, and accessibility controls.

import React from 'react';
import { View, StyleSheet } from 'react-native';

const ViewExample = () => {
  return (
    <View style={styles.container}>
      <View style={styles.box} />
      <View style={styles.box} />
      <View style={styles.box} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'space-around',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  box: {
    width: 80,
    height: 80,
    backgroundColor: 'steelblue',
  },
});

export default ViewExample;

Text

Text displays text and supports nesting, styling, and touch handling.

import React from 'react';
import { Text, StyleSheet } from 'react-native';

const TextExample = () => {

  return (
    <Text style={styles.baseText}>
      This is the base text
      <Text style={styles.nestedText}> and this is nested text</Text>
    </Text>
  );

};

const styles = StyleSheet.create({
  baseText: {
    fontFamily: 'Cochin',
    fontSize: 18,
    fontWeight: 'bold',
  },
  nestedText: {
    color: 'red',
  },

});

export default TextExample;

Image

Image displays different types of images, including network images, static resources, and images from the local disk.

import React from 'react';
import { View, Image, StyleSheet } from 'react-native';

const ImageExample = () => {
  return (
    <View style={styles.container}>
      {/* Loading a local image */}
      <Image
        source={require('./assets/local-image.png')}
        style={styles.localImage}
      />
      {/* Loading a network image */}
      <Image
        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
        style={styles.networkImage}
      />
    </View>
  );

};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  localImage: {
    width: 200,
    height: 200,
    margin: 10,
  },
  networkImage: {
    width: 100,
    height: 100,
    margin: 10,
  },
});

export default ImageExample;

TextInput

TextInput allows users to enter text. It has a wide range of configurable properties to customize the input behavior.

import React, { useState } from 'react';
import { View, TextInput, Text, StyleSheet } from 'react-native';

const TextInputExample = () => {
  const [text, setText] = useState('');
  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Type something here..."
        onChangeText={text => setText(text)}
        value={text}
      />
      <Text style={styles.text}>
        You typed: {text}
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
  },
  input: {
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    paddingHorizontal: 10,
    marginBottom: 20,
  },
  text: {
    fontSize: 16,
  },
});

export default TextInputExample;

ScrollView

ScrollView is a generic scrolling container that can host multiple components and views.

import React from 'react';
import { ScrollView, View, Text, StyleSheet } from 'react-native';

const ScrollViewExample = () => {
  return (
    <ScrollView style={styles.container}>
      {[...Array(20)].map((_, i) => (
        <View key={i} style={styles.box}>
          <Text style={styles.text}>Item {i + 1}</Text>
        </View>
      ))}
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
  },
  box: {
    height: 100,
    marginVertical: 10,
    backgroundColor: 'skyblue',
    justifyContent: 'center',
    alignItems: 'center',
  },

  text: {
    fontSize: 20,
    fontWeight: 'bold',
  },
});
export default ScrollViewExample;

Button

Button provides a basic button component that renders nicely on any platform.

import React from 'react';
import { View, Button, Alert, StyleSheet } from 'react-native';

const ButtonExample = () => {
  return (
    <View style={styles.container}>
      <Button
        title="Press Me"
        onPress={() => Alert.alert('Button pressed!')}
        color="#841584"
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
  },
});
export default ButtonExample;

Touchable Components

React Native provides several touchable components to handle touch events:

  • TouchableHighlight: Changes opacity when pressed
  • TouchableOpacity: Changes opacity when pressed (more customizable)
  • TouchableWithoutFeedback: No visual feedback when pressed
  • Pressable: Modern touchable component with more control over interactions
import React from 'react';
import { View, Text, TouchableHighlight, TouchableOpacity, StyleSheet, Alert } from 'react-native';

const TouchableExample = () => {
  return (
    <View style={styles.container}>
      <TouchableHighlight
        style={styles.button}
        onPress={() => Alert.alert('TouchableHighlight pressed!')}
        underlayColor="#DDDDDD"
      >
        <Text style={styles.buttonText}>TouchableHighlight</Text>
      </TouchableHighlight>
      <TouchableOpacity
        style={styles.button}
        onPress={() => Alert.alert('TouchableOpacity pressed!')}
      >
        <Text style={styles.buttonText}>TouchableOpacity</Text>
      </TouchableOpacity>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
  },
  button: {
    backgroundColor: '#2196F3',
    padding: 15,
    borderRadius: 5,
    marginVertical: 10,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
  },
});

export default TouchableExample;

Switch

Switch is a controlled component that renders a boolean input.

import React, { useState } from 'react';
import { View, Switch, Text, StyleSheet } from 'react-native';

const SwitchExample = () => {
  const [isEnabled, setIsEnabled] = useState(false);
  const toggleSwitch = () => setIsEnabled(previousState => !previousState);
  return (
    <View style={styles.container}>
      <Switch
        trackColor={{ false: "#767577", true: "#81b0ff" }}
        thumbColor={isEnabled ? "#f5dd4b" : "#f4f3f4"}
        ios_backgroundColor="#3e3e3e"
        onValueChange={toggleSwitch}
        value={isEnabled}
      />
      <Text style={styles.text}>
        Switch is {isEnabled ? 'ON' : 'OFF'}
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: "center",
    justifyContent: "center"
  },
  text: {
    marginTop: 20,
    fontSize: 18,
  }
});

export default SwitchExample;

ActivityIndicator

ActivityIndicator displays a loading indicator.

import React, { useState, useEffect } from 'react';
import { View, ActivityIndicator, StyleSheet, Text } from 'react-native';

const ActivityIndicatorExample = () => {
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    // Simulate data loading
    const timer = setTimeout(() => {
      setLoading(false);
    }, 3000);
    return () => clearTimeout(timer);
  }, []);
  return (
    <View style={styles.container}>
      {loading ? (
        <View style={styles.loadingContainer}>
          <ActivityIndicator size="large" color="#0000ff" />
          <Text style={styles.loadingText}>Loading...</Text>
        </View>
      ) : (
        <Text style={styles.content}>Content Loaded!</Text>
      )}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  loadingContainer: {
    alignItems: 'center',
  },
  loadingText: {
    marginTop: 10,
    fontSize: 16,
  },
  content: {
    fontSize: 20,
    fontWeight: 'bold',
  },

});

export default ActivityIndicatorExample;

Custom Components

Creating custom components allows you to build reusable UI elements for your application.

import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';

// Custom Button Component
const CustomButton = ({ title, onPress, backgroundColor = '#2196F3' }) => {
  return (
    <TouchableOpacity 
      style={[styles.button, { backgroundColor }]} 
      onPress={onPress}
    >
      <Text style={styles.buttonText}>{title}</Text>
    </TouchableOpacity>
  );
};

// Using the Custom Component
const CustomComponentExample = () => {
  return (
    <View style={styles.container}>
      <CustomButton 
        title="Primary Button" 
        onPress={() => alert('Primary button pressed!')} 
      />
      <CustomButton 
        title="Secondary Button" 
        onPress={() => alert('Secondary button pressed!')} 
        backgroundColor="#FF9800"
      />
      <CustomButton 
        title="Danger Button" 
        onPress={() => alert('Danger button pressed!')} 
        backgroundColor="#F44336"
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    padding: 20,
  },
  button: {
    padding: 15,
    borderRadius: 5,
    marginVertical: 10,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontWeight: 'bold',
    fontSize: 16,
  },
});

export default CustomComponentExample;

Component Composition

Component composition is a powerful pattern in React Native that involves building complex UIs by combining simpler components.

import React from 'react';
import { View, Text, StyleSheet, Image } from 'react-native';

// Card Header Component
const CardHeader = ({ title, subtitle }) => {
  return (
    <View style={styles.header}>
      <Text style={styles.title}>{title}</Text>
      <Text style={styles.subtitle}>{subtitle}</Text>
    </View>
  );
};

// Card Content Component
const CardContent = ({ children }) => {
  return <View style={styles.content}>{children}</View>;
};

// Card Footer Component
const CardFooter = ({ children }) => {
  return <View style={styles.footer}>{children}</View>;
};

// Card Component that composes the above components
const Card = ({ title, subtitle, image, description, footer }) => {
  return (
    <View style={styles.card}>
      <CardHeader title={title} subtitle={subtitle} />
      <Image source={image} style={styles.image} />
      <CardContent>
        <Text>{description}</Text>
      </CardContent>
      <CardFooter>{footer}</CardFooter>
    </View>
  );
};

// Example Usage
const CompositionExample = () => {
  return (
    <View style={styles.container}>
      <Card
        title="Beautiful Sunset"
        subtitle="Captured yesterday"
        image={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
        description="This stunning sunset was captured at the beach yesterday evening. The colors were absolutely breathtaking."
        footer={
          <Text style={styles.footerText}>Photo by: John Doe</Text>
        }
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 20,
    justifyContent: 'center',
  },
  card: {
    backgroundColor: 'white',
    borderRadius: 10,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.25,
    shadowRadius: 3.84,
    elevation: 5,
    overflow: 'hidden',
  },
  header: {
    padding: 15,
    backgroundColor: '#f8f8f8',
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
  },
  subtitle: {
    fontSize: 14,
    color: '#666',
    marginTop: 5,
  },
  image: {
    width: '100%',
    height: 200,
  },
  content: {
    padding: 15,
  },
  footer: {
    padding: 15,
    borderTopWidth: 1,
    borderTopColor: '#eee',
  },
  footerText: {
    fontSize: 12,
    color: '#666',
    textAlign: 'right',
  },
});

export default CompositionExample;

Platform-Specific Components

React Native allows you to create platform-specific components using the Platform module.

import React from 'react';
import { View, Text, StyleSheet, Platform } from 'react-native';

const PlatformSpecificExample = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.headerText}>
        Platform-Specific Components
      </Text>
      {/* Platform-specific code */}
      {Platform.OS === 'ios' ? (
        <Text style={styles.platformText}>This is rendered only on iOS</Text>
      ) : (
        <Text style={styles.platformText}>This is rendered only on Android</Text>
      )}
      {/* Platform-specific styles */}
      <View style={styles.box}>
        <Text style={styles.boxText}>
          This box has platform-specific styling
        </Text>
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },

  headerText: {
    fontSize: 24,
    fontWeight: 'bold',
    marginBottom: 20,
  },

  platformText: {
    fontSize: 16,
    color: 'blue',
    marginBottom: 20,
  },

  box: {
    width: 200,
    height: 100,
    justifyContent: 'center',
    alignItems: 'center',
    ...Platform.select({
      ios: {
        backgroundColor: '#FFCCCC',
        shadowColor: '#000',
        shadowOffset: { width: 0, height: 2 },
        shadowOpacity: 0.25,
        shadowRadius: 3.84,
      },
      android: {
        backgroundColor: '#CCFFCC',
        elevation: 5,
      },
    }),
  },

  boxText: {
    textAlign: 'center',
    ...Platform.select({
      ios: {
        color: 'red',
      },
      android: {
        color: 'green',
      },
    }),
  },
});

export default PlatformSpecificExample;

Component Best Practices

1. Keep Components Small and Focused

Components should ideally do one thing well. If a component becomes too complex, consider breaking it down into smaller, more manageable pieces.

2. Use Consistent Naming Conventions

Use descriptive names for your components. Component names should be in PascalCase (e.g., UserProfile, NavigationHeader).

3. Optimize Performance with React.memo

Use React.memo to prevent unnecessary re-renders of functional components.

import React from 'react';
import { Text } from 'react-native';

const ExpensiveComponent = React.memo(({ data }) => {
  console.log('Rendering ExpensiveComponent');
  return <Text>{data}</Text>;
});

export default ExpensiveComponent;

4. Separate Logic from UI

Keep your component logic separate from your UI rendering. This makes your code more maintainable and testable.

5. Avoid Deeply Nested Components

Deep component nesting can make your code hard to follow and debug. Try to keep your component hierarchy relatively flat.

Summary

In this chapter, we’ve explored:

  • What React Native components are and their types
  • Core components provided by React Native, including View, Text, Image, and more
  • How to create custom components
  • Component composition techniques
  • Platform-specific components
  • Best practices for creating and managing components

Components are the building blocks of React Native applications. Understanding how to use and combine them effectively is crucial for creating robust, maintainable, and performant mobile applications. As you continue your React Native journey, you’ll discover more advanced component patterns and techniques.

Exercises

  1. Create a simple counter app using functional components and the useState hook.
  2. Build a custom button component that accepts props for customization.
  3. Create a card component that displays an image, title, and description.
  4. Build a form with TextInput components and validation.
  5. Create a platform-specific component that displays differently on iOS and Android.

In the next chapter, we’ll dive deeper into state and props in React Native, which will allow you to create dynamic and interactive components.

Related Articles:

Scroll to Top