Skip to content
Advertisement

What is wrong with the React components Route?

Attempting to build a flashcard app with React and React Hooks, I am able to get my home screen rendered. When introducing Router, I am able to click the link, update the path to be the one I am looking for, but nothing is being rendered from that new page.

App.js

import React, {useState, useEffect} from "react";
import Header from "./Header";
import NotFound from "./NotFound";
import ShowAllDecks from './ShowAllDecks';
import axios from 'axios';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';

function Layout() {
  const [flashcards, setFlashcards] = useState([])

  //Delete a deck of flashcards
  const deleteHandler = (id) => {
    const result = window.confirm('Are you sure you want to delete?'); 
    if (result) {
      setFlashcards(flashcards.filter(deck => deck.id !== id));
    };
 };

  useEffect(() => {
    axios
    .get('http://localhost:5000/decks?_embed=cards')
    .then(res => {
      setFlashcards(res.data.map((questionItem, index) => {

        return {
          id: `${index}-${Date.now()}`,
          name: questionItem.name,
          description: questionItem.description,
          cards: questionItem.cards.length,
        }
      }))
    })
  }, [])

  return (
    <div>
      <Header />
      <Router>
        <Switch>
          <Route exact={true} path={'/'}>
            <ShowAllDecks flashcards={flashcards} setFlashcards={setFlashcards} deleteHandler={deleteHandler} />
          </Route>
        </Switch>
      </Router>
      <NotFound />
    </div>
  )

}

ShowAllDecks.js –> List of flashcard decks

import React from 'react';
import Deck from './Deck';
import ViewDeck from './ViewDeck';

function ShowAllDecks({ flashcards, deleteHandler }) {

    return (
        <div className='container'>
            <button>Create New</button>
            {flashcards.map((flashcard) => {
                return (
                    <Deck flashcards={flashcards} flashcard={flashcard} key={flashcard.id} deleteHandler={deleteHandler} />
                )
            })}
        </div>
    )
}

export default ShowAllDecks;

Deck.js –> Individual deck of flashcards

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import ViewDeck from './ViewDeck';

function Deck({ flashcard, flashcards, setFlashcards, deleteHandler}) {

    return (
        <div className='container'>
            <div className='card'>
            <div className='card-body'>
                <h3 className='card-title'>{flashcard.name}</h3>
                <p className='card-text'>{flashcard.description}</p>
                <p className='card-text'>{flashcard.cards} cards</p>
                <Link to={`decks/${flashcard.id}`}>View</Link>
                <button>Study</button>
                <button onClick={() => deleteHandler(flashcard.id)}><i className="fas fa-trash" /></button>
            </div>
            <Router>
                <Switch>
                    <Route exact={true} path={`decks/${flashcard.id}`}>
                        <ViewDeck flashcards={flashcards} flashcard={flashcard} deleteHandler={deleteHandler} />
                    </Route>
                </Switch>
            </Router>
            </div>

        </div>
    )
}

export default Deck;

ViewDeck.js –> Should be a new screen for individual flashcard deck where I can view the list of cards in the deck, edit the cards, or add new cards.

import React from 'react';

function ViewDeck({ flashcards, flashcard, deleteHandler }) {
    console.log(flashcards)
    return (
        <p>{flashcards.name}</p>
    )
}
 
export default ViewDeck;

When on the index route, flashcards is an array of objects and flashcard is a deck of cards object. What am I doing wrong with my Routes or components that make my component not render?

Example of the URL:

[
  {
    "id": 1,
    "name": "Rendering in React",
    "description": "React's component structure allows for quickly building a complex web application that relies on DOM manipulation. ",
    "cards": [
      {
        "id": 1,
        "front": "Differentiate between Real DOM and Virtual DOM.",
        "back": "Virtual DOM updates are faster but do not directly update the HTML",
        "deckId": 1
      },
      {
        "id": 2,
        "front": "How do you modify the state of a different React component?",
        "back": "Not at all! State is visible to the component only.",
        "deckId": 1
      },
      {
        "id": 3,
        "front": "How do you pass data 'down' to a React child component?",
        "back": "As properties or props",
        "deckId": 1
      },
      {
        "cards": [],
        "front": "b",
        "back": "b",
        "deckId": 1,
        "id": 7
      }
    ]
  }
]

Advertisement

Answer

Since in your Sandbox you left the Deck element empty, I had to come up with my own:

          <div>
            Card Name: {flashcard.name}
            <br />
            <Link to={`/decks/${flashcard.id}`}>click on card</Link>
          </div>

But the idea is simple, you need to define your Routes at the higher level and then just create links to the routes inside your Deck element. Here is how your route definitions should look:

      <Router>
        <Switch>
          <Route exact={true} path={"/"}>
            <ShowAllDecks
              flashcards={flashcards}
              setFlashcards={setFlashcards}
              deleteHandler={deleteHandler}
            />
          </Route>
        </Switch>

        {flashcards.map((item, i) => (
          <Switch key={i}>
            <Route exact path={`/decks/${item.id}`}>
              <ViewDeck flashcard={item} deleteHandler={deleteHandler} />
              {/* <div>Some stuff here</div> */}
            </Route>
          </Switch>
        ))}
      </Router>

Here is a working Sandbox.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement