Home > front end >  React Router throws error with certain component
React Router throws error with certain component

Time:10-03

I would like to implement routing in my project but I keep getting the same error message and can't figure out how to solve the problem. I want to start with the MappedCharacters component and assign it to the "/" route. Here I get the following error message: "Uncaught Error: [MappedCharacters] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>".

I have also set the browser router in Index.js (so that can't be the problem). As soon as I remove the MappedCharacters component it works. So how could I wrap MappedCharacters to make routing work?

App.js

import "./App.css";
import Header from "./components/Header";
/* import styled from "styled-components"; */
import Navbar from "./components/Navbar";
import { useState, useEffect } from "react";
import MappedCharacters from "./components/MappedCharacters";
import AddFavorites from "./components/AddFavorites";
import SearchBox from "./components/Searchbox";
import { Routes, Route, useNavigate } from "react-router-dom";

const URL = 'https://rickandmortyapi.com/api/character'; /* Das hier ist der API Link in einer Variablen */

function App() {
  const [characters, setCharacters] = useState([]);
  const [hasError, setHasError] = useState(false)
  const [favorites, setFavorites] = useState([])
  const [searchValue, setSearchValue] = useState([])

  /* Hier folgend wird von der API gefetched */
  async function fetchCharacters() {
    try {
      const response = await fetch(URL);
      const result = await response.json() 
      setCharacters(result.results);
      setHasError(false);
    }
    catch(error) {
    setHasError(true);
    console.error(error);
    }
  }
 /*  Ohne den useEffect klappt das fetchen und rendern der Cards nicht!!! */
  useEffect(() => { 
    fetchCharacters();
  }, []);

  const addFavoriteCharacter = (character) => {
    const newFavoriteList = [...favorites, character];
    setFavorites(newFavoriteList);
  }

  return (
    <div className="App">
      <Header />
     
      <SearchBox searchValue={searchValue} setSearchValue={setSearchValue} />
      <Routes>
        <Route path="/">
          {characters.map((character) => (
            <MappedCharacters
              name={character.name}
              gender={character.gender}
              status={character.status}
              species={character.species}
              image={character.image}
              favoriteComponent={AddFavorites}
              handleFavoritesClick={addFavoriteCharacter}
            />
          ))}
        </Route>
      </Routes>
      <Navbar />
    </div>
  )
}

export default App;

/* const CardElements = styled.li`
color: whitesmoke;
list-style: none;
`; */

index.js

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import { BrowserRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

reportWebVitals();

MappedCharacters.js

import React from 'react'

const MappedCharacters = (props) => {
  const FavoriteComponent = props.favoriteComponent;
  return (
    <div>
      <li key={props.id} >
        <h1>{props.name}</h1>
        <p>Gender: {props.gender}</p>
        <p>Status: {props.status}</p>
        <p>Species: {props.species}</p>
        <div>
          <img src={props.image} alt="img"></img>
        </div>
        <FavoriteComponent />
      </li>
    </div>
  )
}

export default MappedCharacters

CodePudding user response:

Issue

The issue is with this route:

<Route path="/">
  {characters.map((character) => (
    <MappedCharacters
      name={character.name}
      gender={character.gender}
      status={character.status}
      species={character.species}
      image={character.image}
      favoriteComponent={AddFavorites}
      handleFavoritesClick={addFavoriteCharacter}
    />
  ))}
</Route>

As the error indicates, only other Route or React.Fragment components are valid children of the Route component. Match routed content should be rendered on the Route component's element prop.

Solution

Move the characters array mapping into the element prop.

<Route
  path="/"
  element={(
    <>
      {characters.map((character) => (
        <MappedCharacters
          key={character.id} // <-- don't forget valid React key!
          name={character.name}
          gender={character.gender}
          status={character.status}
          species={character.species}
          image={character.image}
          favoriteComponent={AddFavorites}
          handleFavoritesClick={addFavoriteCharacter}
        />
      ))}
    </>
  )}
/>

Or abstract the mapping into a React component and pass the characters array as a prop.

const Characters = ({ addFavoriteCharacter, characters }) => (
  <>
    {characters.map((character) => (
      <MappedCharacters
        key={character.id} // <-- don't forget valid React key!
        name={character.name}
        gender={character.gender}
        status={character.status}
        species={character.species}
        image={character.image}
        favoriteComponent={AddFavorites}
        handleFavoritesClick={addFavoriteCharacter}
      />
    ))}
  </>
);

...

<Route
  path="/"
  element={<Characters {...{ addFavoriteCharacter, characters }} />}
/>

Edit react-router-throws-error-with-certain-component

CodePudding user response:

You can do as MrBens says. You could also use a Fragment:

<Route path="/">
    <>{characters.map((character) => (
        <MappedCharacters
            name={character.name}
            gender={character.gender}
            status={character.status}
            species={character.species}
            image={character.image}
            favoriteComponent={AddFavorites}
            handleFavoritesClick={addFavoriteCharacter}
        />
    ))}</>
</Route>

CodePudding user response:

You cannot pass a list of components as children to the Route object.
Children has to be React.ReactNode (which can be a single react component).
So what you can do instead is pass a single wrapper component, CharactersList that accepts your character list, and map it accordingly:

<Route path="/">
  <CharactersList characters={characters}/>
</Route>

and in CharactersList.jsx create something like this:

const CharactersList = ({ characters }) => {
  return (
    <>
      {characters.map((character) => (
        <MappedCharacters
          name={character.name}
          gender={character.gender}
          status={character.status}
          species={character.species}
          image={character.image}
          favoriteComponent={AddFavorites}
          handleFavoritesClick={addFavoriteCharacter}
       />)
      )}
    </>
  )
}

Check the docs for more info

  • Related