React Native - Routing with IDs

This lesson is part of a series on React Native.

Step 15 - Routing for Books

Add a file named books.js to your project folder and put this into it:

export const bookData = [
  {
    id: "1",
    title: "The Pragmatic Programmer",
    author: "Andrew Hunt & David Thomas",
    summary: "A classic book about practical software development principles."
  },
  {
    id: "2",
    title: "Clean Code",
    author: "Robert C. Martin",
    summary: "Focuses on writing readable, maintainable, and clean code."
  },
  {
    id: "3",
    title: "You Don't Know JS",
    author: "Kyle Simpson",
    summary: "A deep dive into how JavaScript really works."
  }
];

Add these Stack.Screen elements to app/_layout.js:

<Stack.Screen name="books/index" options={{ title: "Books"}} />
<Stack.Screen name="books/[id]" options={{ title: "Book Details"}} />

Add this to the CustomScreen element in app/index.jsx:

<Link href="/books">Books</Link>

Add a folder named books to the app folder.

Then add a file named index.jsx to the books folder, and put this into it:

import { StyleSheet, Text, View } from 'react-native'
import {Link} from 'expo-router'
import {useEffect, useState} from 'react'
import {bookData} from '../../books'
import CustomScreen from '../../components/CustomScreen'
import CustomText from '../../components/CustomText'

const index = () => {

  const [books, setBooks] = useState([]);

  useEffect(() => {
    // We would normally do an API call here to get the books
    setBooks(bookData)
  }, [])

  return (
    <CustomScreen>
      {books.map( b => <Link key={b.id} href={"/books/" + b.id}>
                        <CustomText title>{b.title}</CustomText>
                       </Link>)}
    </CustomScreen>
  )
}

export default index

const styles = StyleSheet.create({})

Run the app and navigate to the books index page.

We should really use a FlatList instead of generating all the Link elements with books.map(). Don't forget to import FlatList, then update the returned JSX to look like this:

<CustomScreen>
  <FlatList 
    data={books} 
    renderItem={({item}) => <Link key={item.index} href={"/books/" + item.id}><CustomText>{item.title}</CustomText></Link>} />
</CustomScreen>

Creating a Book Details component

Create a file named [id].jsx in the books folder.

Note that what you put inside the square brackets makes anything that comes after /books/ a param that you can access from your code.

Put this code inside the [id].jsx file:

import { View, Text, StyleSheet } from "react-native";
import { useLocalSearchParams } from "expo-router";
import CustomScreen from "../../components/CustomScreen";
import CustomText from "../../components/CustomText";

const BookDetails = () => {

  const {id} = useLocalSearchParams();

  return (
    <CustomScreen>
      <CustomText>BOOK: {id}</CustomText>
    </CustomScreen>
  )
}

export default BookDetails

const styles = StyleSheet.create({})

Run the app, and notice how the book id is displayed in the BookDetails component.

Modify the [id].jsx file to look like this:

import { View, Text, StyleSheet } from "react-native";
import { useLocalSearchParams } from "expo-router";
import CustomScreen from "../../components/CustomScreen";
import CustomText from "../../components/CustomText";

// Add these imports
import {bookData} from '../../books'
import {useState, useEffect} from 'react'

const BookDetails = () => {

  const {id} = useLocalSearchParams();

  // Add book state (initialize to an empyt obj)
  const [book, setBook] = useState({});

  // Add useEffect to get the book that matches the id
  useEffect(() => {
    // You might do an API call to get the book from the backend here
    setBook(bookData.find(b => b.id === id))
  }, [])

  return (
    <CustomScreen>
      
      /////// Modify the elements inside the CustomScreen element
      <CustomText title>{book.title}</CustomText>
      <CustomText>{book.author}</CustomText>
      <Text>{book.summary}</Text>

    </CustomScreen>
  )
}

export default BookDetails

const styles = StyleSheet.create({})