Lesson 04-React Native Components and APIs

Common Components

React Native’s core components are the building blocks for creating user interfaces. Below are four of the most commonly used components: View, Text, TextInput, and TouchableOpacity.

View: Layout Container

View is the most fundamental layout component in React Native, similar to HTML’s <div>, used to organize and arrange other components.

Example Code

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

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

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f0f0f0',
  },
  box: {
    width: 100,
    height: 100,
    backgroundColor: 'skyblue',
    margin: 10,
  },
});

export default App;

Analysis

  • flex: 1: Makes the View fill its parent container.
  • justifyContent and alignItems: Control the alignment of child elements.
  • StyleSheet.create: Creates style objects, improving performance and enabling code autocompletion.

Text: Text Display

Text is used to display text, supporting nesting and rich styling.

Example Code

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

const App = () => {
  return (
    <View style={styles.container}>
      <Text style={styles.title}>Hello, React Native!</Text>
      <Text>
        This is a <Text style={styles.bold}>bold</Text> text.
      </Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  title: { fontSize: 24, color: 'blue' },
  bold: { fontWeight: 'bold' },
});

export default App;

Analysis

  • Text Nesting: Supports nesting Text components for localized styling.
  • Style Inheritance: Child Text components inherit parent styles unless explicitly overridden.

TextInput: Input Field

TextInput captures user input and supports various properties like placeholders and keyboard types.

Example Code

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

const App = () => {
  const [text, setText] = useState('');

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Enter your name"
        value={text}
        onChangeText={setText}
      />
      <Text>You entered: {text}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  input: {
    width: 200,
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    paddingHorizontal: 10,
  },
});

export default App;

Analysis

  • value and onChangeText: Control input content via state.
  • placeholder: Displays placeholder text.
  • Styling: Uses borderWidth and padding to enhance the input field’s appearance.

TouchableOpacity: Touchable Button

TouchableOpacity is a clickable component that provides a fading opacity effect on press.

Example Code

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

const App = () => {
  const [count, setCount] = useState(0);

  return (
    <View style={styles.container}>
      <TouchableOpacity style={styles.button} onPress={() => setCount(count + 1)}>
        <Text style={styles.buttonText}>Press Me</Text>
      </TouchableOpacity>
      <Text>Count: {count}</Text>
    </View>
  );
};

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

export default App;

Analysis

  • onPress: Defines the click event.
  • Opacity Effect: By default, pressing triggers a slight opacity change, adjustable via activeOpacity.

Images and Animations

Image: Image Display

Image displays local or network images, supporting various loading methods.

Example Code

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

const App = () => {
  return (
    <View style={styles.container}>
      {/* Local Image */}
      <Image
        source={require('./assets/sample.jpg')}
        style={styles.image}
      />
      {/* Network Image */}
      <Image
        source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
        style={styles.image}
      />
    </View>
  );
};

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

export default App;

Analysis

  • require: Loads local images with a static path.
  • uri: Loads network images with dynamic URLs.
  • Performance Tip: Set resizeMode (e.g., cover, contain) to optimize image display.

Animated: Animation Implementation

Animated provides a declarative API for smooth UI interactions.

Example Code

import React, { useRef, useEffect } from 'react';
import { View, Animated, Button, StyleSheet } from 'react-native';

const App = () => {
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 2000,
      useNativeDriver: true,
    }).start();
  }, [fadeAnim]);

  return (
    <View style={styles.container}>
      <Animated.View style={[styles.box, { opacity: fadeAnim }]} />
      <Button
        title="Reset Animation"
        onPress={() => {
          fadeAnim.setValue(0);
          Animated.timing(fadeAnim, {
            toValue: 1,
            duration: 2000,
            useNativeDriver: true,
          }).start();
        }}
      />
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  box: { width: 100, height: 100, backgroundColor: 'tomato' },
});

export default App;

Analysis

  • Animated.Value: Creates an animation value.
  • Animated.timing: Defines a timed animation from an initial to a target value.
  • useNativeDriver: Uses native drivers for better performance.
  • Reset Animation: Resets the animation value with setValue and re-runs it.

Network Requests

Using fetch for Network Requests

fetch is a built-in JavaScript API for network requests, natively supported in React Native.

Example Code

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

const App = () => {
  const [data, setData] = useState(null);

  const fetchData = async () => {
    try {
      const response = await fetch('https://jsonplaceholder.typicode.com/posts/1');
      const json = await response.json();
      setData(json);
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <View style={styles.container}>
      <Button title="Fetch Data" onPress={fetchData} />
      {data && (
        <Text>
          Title: {data.title}
        </Text>
      )}
    </View>
  );
};

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

export default App;

Analysis

  • fetch: Initiates an HTTP request, returning a Promise.
  • Error Handling: Uses try/catch to catch exceptions.
  • Asynchronous Updates: Updates the UI via state.

Using axios to Simplify Requests

axios is a popular third-party library offering a simpler API and automated error handling.

Installation

npm install axios

Example Code

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

const App = () => {
  const [data, setData] = useState(null);

  const fetchData = () => {
    axios.get('https://jsonplaceholder.typicode.com/posts/1')
      .then(response => setData(response.data))
      .catch(error => console.error('Error:', error));
  };

  return (
    <View style={styles.container}>
      <Button title="Fetch Data" onPress={fetchData} />
      {data && (
        <Text>
          Title: {data.title}
        </Text>
      )}
    </View>
  );
};

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

export default App;

Analysis

  • axios.get: Provides concise GET request syntax.
  • Automatic Parsing: Returns JSON data directly, no manual parsing needed.
  • Chained Calls: Supports Promise-based .then and .catch.

Local Storage

AsyncStorage: Key-Value Storage

AsyncStorage is React Native’s asynchronous key-value storage API, ideal for storing small amounts of data (e.g., user settings).

Installation

In newer versions, AsyncStorage is a community package:

npm install @react-native-async-storage/async-storage

Example Code

import React, { useState, useEffect } from 'react';
import { View, Text, TextInput, Button, StyleSheet } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';

const App = () => {
  const [input, setInput] = useState('');
  const [storedValue, setStoredValue] = useState('');

  useEffect(() => {
    loadData();
  }, []);

  const saveData = async () => {
    try {
      await AsyncStorage.setItem('myKey', input);
      setStoredValue(input);
      setInput('');
    } catch (error) {
      console.error('Error saving data:', error);
    }
  };

  const loadData = async () => {
    try {
      const value = await AsyncStorage.getItem('myKey');
      if (value !== null) {
        setStoredValue(value);
      }
    } catch (error) {
      console.error('Error loading data:', error);
    }
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        value={input}
        onChangeText={setInput}
        placeholder="Enter text"
      />
      <Button title="Save" onPress={saveData} />
      <Text>Stored Value: {storedValue}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  input: {
    width: 200,
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginBottom: 10,
    paddingHorizontal: 10,
  },
});

export default App;

Analysis

  • setItem: Stores a key-value pair.
  • getItem: Retrieves a stored value.
  • Asynchronous Operations: All operations return Promises, requiring async/await.

Comprehensive Case Study

Requirement Analysis

We aim to build a simple application that:

  • Displays an input field and button to save user input locally.
  • Shows a post title fetched from a network request.
  • Includes an image with a fade-in animation.

Code Implementation and Analysis

import React, { useState, useEffect, useRef } from 'react';
import {
  View,
  Text,
  TextInput,
  TouchableOpacity,
  Image,
  Animated,
  StyleSheet,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios from 'axios';

const App = () => {
  const [input, setInput] = useState('');
  const [storedValue, setStoredValue] = useState('');
  const [postTitle, setPostTitle] = useState('');
  const fadeAnim = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    loadData();
    fetchData();
    Animated.timing(fadeAnim, {
      toValue: 1,
      duration: 2000,
      useNativeDriver: true,
    }).start();
  }, [fadeAnim]);

  const saveData = async () => {
    try {
      await AsyncStorage.setItem('userInput', input);
      setStoredValue(input);
      setInput('');
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const loadData = async () => {
    try {
      const value = await AsyncStorage.getItem('userInput');
      if (value !== null) {
        setStoredValue(value);
      }
    } catch (error) {
      console.error('Error:', error);
    }
  };

  const fetchData = async () => {
    try {
      const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
      setPostTitle(response.data.title);
    } catch (error) {
      console.error('Error:', error);
    }
  };

  return (
    <View style={styles.container}>
      <Animated.View style={{ opacity: fadeAnim }}>
        <Image
          source={{ uri: 'https://reactnative.dev/img/tiny_logo.png' }}
          style={styles.image}
        />
      </Animated.View>
      <TextInput
        style={styles.input}
        value={input}
        onChangeText={setInput}
        placeholder="Enter something"
      />
      <TouchableOpacity style={styles.button} onPress={saveData}>
        <Text style={styles.buttonText}>Save</Text>
      </TouchableOpacity>
      <Text>Stored: {storedValue}</Text>
      <Text>Post Title: {postTitle}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
  image: { width: 100, height: 100, marginBottom: 20 },
  input: {
    width: 200,
    height: 40,
    borderColor: 'gray',
    borderWidth: 1,
    marginBottom: 10,
    paddingHorizontal: 10,
  },
  button: {
    backgroundColor: 'blue',
    padding: 10,
    borderRadius: 5,
    marginBottom: 10,
  },
  buttonText: { color: 'white', fontSize: 16 },
});

export default App;

Analysis

  • Component Composition: Uses View for layout, TextInput for input, and TouchableOpacity for triggering saves.
  • Animation: The image fades in using Animated.
  • Network Request: Fetches a post title using axios.
  • Local Storage: Saves and loads user input with AsyncStorage.

Advanced Techniques and Considerations

Component Performance Optimization

  • Use React.memo: Prevents unnecessary re-renders. const MyComponent = React.memo(() => <Text>Static Content</Text>);
  • Minimize Style Computations: Reuse styles defined in StyleSheet.

Animation Optimization

  • Parallel Animations: Use Animated.parallel to run multiple animations simultaneously.
  • Sequential Animations: Use Animated.sequence to execute animations in order.

Network Request Error Handling

  • Timeout Setting: axios.get(url, { timeout: 5000 });
  • Retry Mechanism: Implement simple retry logic.
const fetchWithRetry = async (url, retries = 3) => {
  for (let i = 0; i < retries; i++) {
    try {
  	const response = await axios.get(url);
  	return response.data;
    } catch (error) {
  	if (i === retries - 1) throw error;
  	await new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
};

Share your love