Reputation: 35
Why Am I unable to map through a list and create routes with this code 👇
import { useEffect } from "react";
import { Route, Routes } from "react-router-dom";
import "./App.css";
function App() {
const array1 = [];
const array2 = [];
useEffect(() => {
array1.push({ name: "dev", bio: "yeah" });
array1.push({ name: "kirath", bio: 'yeah it"s big brain time' });
console.log(array1);
array1.map((object) => {
array2.push(object.name);
});
}, []);
return (
<div className="App">
<Routes>
{array2.map((name) => {
return <Route path={`/${name}`} element={<h1>hello {name}</h1>} />;
})}
</Routes>
</div>
);
}
export default App;
i have tried to look at a lot of different ways but unable to do so...My actual motive is to connect this to firebase realtime database but i just hard coded the data for now because i was unable to create routes with this type of data why?
Upvotes: 2
Views: 634
Reputation: 203218
The main issue is that there is no React state and the variables you are mutating are being updated after the component has rendered since the useEffect
hook runs at the end of the render cycle. In other words, the component renders with array1
and array2
being empty, then the useEffect
hook callback is called and the arrays are mutated. Since there is no state involved there is nothing to trigger a rerender. This wouldn't matter though because even if you did manage to trigger another render cycle the array1
and array2
arrays would be redeclared again as empty arrays and the issue would remain the same.
function App() {
const array1 = []; // <-- declared empty each render cycle
const array2 = []; // <-- declared empty each render cycle
useEffect(() => {
array1.push({ name: "dev", bio: "yeah" });
array1.push({ name: "kirath", bio: 'yeah it"s big brain time' });
console.log(array1);
array1.map((object) => {
array2.push(object.name);
});
}, []);
return (
<div className="App">
<Routes>
{array2.map((name) => { // <-- always empty when rendered
return <Route path={`/${name}`} element={<h1>hello {name}</h1>} />;
})}
</Routes>
</div>
);
}
The arrays should be declared declared in state if you want to update them via the useEffect
. Instead of two arrays, just use a single array and when mapping to JSX access the name
property.
function App() {
const [people, setPeople] = React.setState([]);
useEffect(() => {
setPeople([
{ name: "dev", bio: "yeah" },
{ name: "kirath", bio: 'yeah it"s big brain time' },
]);
}, []);
return (
<div className="App">
<Routes>
{people.map(({ name }) => {
return <Route path={`/${name}`} element={<h1>hello {name}</h1>} />;
})}
</Routes>
</div>
);
}
Of course, if you already know what the array contents will be it would be better to just initialize the array value so the values are available on the initial render.
function App() {
const [people, setPeople] = React.setState([
{ name: "dev", bio: "yeah" },
{ name: "kirath", bio: 'yeah it"s big brain time' },
]);
return (
<div className="App">
<Routes>
{people.map(({ name }) => {
return <Route path={`/${name}`} element={<h1>hello {name}</h1>} />;
})}
</Routes>
</div>
);
}
Another improvement I'd suggest is to only render a single route with a dynamic path parameter.
Example:
const Person = () => {
const { name } = useParams();
return <h1>hello {name}</h1>;
};
function App() {
const [people, setPeople] = React.setState([]);
useEffect(() => {
... business logic to fetch people from firebase ...
}, []);
return (
<div className="App">
<ul>
{people.map(({ name }) => (
<li>
<Link to={`/${name}`}>{name}</Link>
</li>
))}
</ul>
<Routes>
<Route path="/:name" element={<Person />} />
</Routes>
</div>
);
}
Upvotes: 0
Reputation: 354
Try this.
import { useEffect } from "react";
import { Route, Routes } from "react-router-dom";
import "./App.css";
function App() {
const array1 = [];
const [array2, setArray2] = useState([]);
useEffect(() => {
array1.push({ name: "dev", bio: "yeah" });
array1.push({ name: "kirath", bio: 'yeah it"s big brain time' });
console.log(array1);
const newArray = array1.map((object) => object.name);
setArray2(newArray);
}, []);
return (
<div className="App">
<Routes>
{array2.map((name) => {
return <Route path={`/${name}`} element={<h1>hello {name}</h1>} />;
})}
</Routes>
</div>
);
}
export default App;
Upvotes: 1
Reputation: 42
Just replace Routes with Switch and try it.
import { Route, Switch } from "react-router-dom";
// code
<Switch>
`{array2.map((name) => {
return <Route path={`/${name}`} element={<h1>hello {name}</h1>}/> })}`
</Switch>
Upvotes: 0
Reputation: 354
Your array2
is constant and not state
, that is why at first render it is an empty array.
You push items to array2
but your component does not rerender.
You need to do it like this.
const [array2, setArray2] = useState([])
and in useEffect
you need to
const newPushedArray = array1.map(name) => <Route path={`/${name}`} element={<h1>hello {name}</h1>} />
setArray2(newPushedArray)
Upvotes: 1