Search code examples
javascriptreactjsreact-routeriterablereact-state

Reac router component in a list as a state


does anyone have experience with React routers?Is there a way to create a list of routes and hold it in a usestate? When i try to do the [... prevCountryRoutes] i get the error that prevCountryRoutes is not iterable

 const [countriesWithRouteList,setCountriesWithRouteList]=React.useState(JSON.parse(localStorage.getItem("countriesWithRouteList")) || [])
 const [countryRoutes,setCountryRoutes]=React.useState()

function addCountryRoute(co){
   if(countriesWithRouteList.filter(el => el == co) == null){
     console.log('already route exists')
   }else{
     console.log('country page being added')
     setCountryRoutes((prevCountryRoutes)=>{
       const newRoute = <Route 
         key={nanoid()}
         path={`/countrypage/${co.replace(/ /g, '%20')}`} 
         element={
           <CountryPage 
             country={co}
             holidays={holidays}
             handleDeleteClick={handleDeleteClick}
             handleFormSubmit={handleFormSubmit}
           />
         }
       />
       return(
         [...prevCountryRoutes, newRoute]
       )
     })
   }
   setCountriesWithRouteList(prevList => [...prevList, co])
 }

Solution

  • The error you are asking about is cause by not declaring an initial countryRoutes state that is iterable. It's undefined.

    Anyway, it's a React anti-pattern to store React components and JSX in state. Just store the data and render the derived JSX from state.

    I suggest the following refactor:

    const [countries, setCountries] = React.useState(JSON.parse(localStorage.getItem("countries")) || []);
    
    function addCountryRoute(co){
      if (countries.some(el => el.co === co)){
        console.log('already route exists')
      } else {
        console.log('country page being added')
        setCountries((countries) => countries.concat({
          id: nanoid(),
          co,
        }));
      }
    }
    
    ...
    
    {countries.map(country => (
      <Route 
        key={country.id}
        path={`/countrypage/${co.replace(/ /g, '%20')}`} 
        element={
          <CountryPage 
            country={co}
            holidays={holidays}
            handleDeleteClick={handleDeleteClick}
            handleFormSubmit={handleFormSubmit}
          />
        }
      />
    ))}
    

    And instead of mapping a bunch of routes that differ only in the country path segment, render just a single route where the country code is a route path parameter and the CountryPage component uses the useParams hook to get the code.

    Example:

    <Route 
      path="/countrypage/:country" 
      element={
        <CountryPage
          holidays={holidays}
          handleDeleteClick={handleDeleteClick}
          handleFormSubmit={handleFormSubmit}
        />
      }
    />
    

    CountryPage

    const { country } = useParams();