I am running a function when the user clicks a button, this function updates my useState
and adds an array into it as data. This data later on is passed into another webpage where the array objects are displayed in a different way. I'm running into an issue where, my useState
is not updating and instead returns an empty array. I suspect it has something to do with the new page refreshing and not updating the useState
. I am just not sure where to go from here.
I am using React-Router V6 for this
Here is my Parent webpage along with the button.
<div className="toggleButtons" key={id}>
<Link
to={"/DetailsPage"}
onClick={toggledItem}
state={{ data: data }}
className="primary-ff boxyButton"
>
{buttonText}
</Link>
<a href={link} className="icon-link" target="_blank">
<i className="fa-solid fa-arrow-up-right-from-square"></i>
</a>
</div>
Here is where I am trying to pass an array list into my useState
const softiesInfo = pageContentList.find(({id}) => id == 1);
const palcoInfo = pageContentList.find(({id}) => id == 2);
const tlaxInfo = pageContentList.find(({id}) => id == 3);
const [data, setData] = useState({})
const toggledItem = () => {
if (id === 1) {
setData(softiesInfo);
} else if (id === 2) {
setData(palcoInfo)
} else {
setData(tlaxInfo)
}
};
Here is where my data should be rendered on my second page.
export default function DetailsPage() {
const location = useLocation();
const data = location.state;
return (
<div className="header-wrap">
<h1 className="primary-ff">{data.title}</h1>
<img src={data.logoImg} alt={data.altLogo} />
</div>
)
});
I tried force feeding the data into my useState
like this and this resulted successful, but I don't see it being very efficient and would count as writing clean code.
const [data, setData] = useState({
sectionName: "softies-section",
title: "Softies Ice Cream-Under The Scoop",
logoImg: softieslogo,
altLogo: "softies-logo",
img: softiesPlanner,
altImg: "Career Day At Pinnacle",
img2: softiesAccordion,
constrainContent:
"lorem a;sdkfj;alskdjfa lksdfjlaksjdl;fkjasldk;fjaslkdfjal;sdkjfalksdjf;laks;dj asflsngealj sflsdajflkads",
id: 1,
});
The issue here is that the Link
component effects a navigation action immediately when it is clicked, and the passed state
prop will include whatever the data
value is at the time the link is clicked.
The DetailsPage
also isn't accessing into the passed state reference the data
property, it's only declaring a local variable named data
and setting it to the value of location.state
. DetailsPage
would need to access data.data.title
to get the passed information.
You can prevent the default link action from happening and effect the navigation action manually later. Unfortunately because enqueued React state updates are processed asynchronously you also can't use the data
state in the route state. What you can do however is to enqueue the state update alongside the imperative navigation action with the same value.
Example:
import { Link, useNavigate } from 'react-router-dom';
...
const navigate = useNavigate();
...
const toggledItem = (e) => {
e.preventDefault(); // <-- prevent link navigation
let data = {};
switch(id) {
case 1:
data = softiesInfo;
break;
case 2:
data = palcoInfo;
break;
case 3:
default:
data = tlaxInfo;
break;
}
setData(data);
navigate( // <-- imperative navigation
"/DetailsPage",
{ state: { data } }
);
};
...
<Link
to="/DetailsPage"
onClick={toggledItem}
className="primary-ff boxyButton"
>
{buttonText}
</Link>
export default function DetailsPage() {
const location = useLocation();
const { data } = location.state ?? {};
return (
<div className="header-wrap">
<h1 className="primary-ff">{data.title}</h1>
<img src={data.logoImg} alt={data.altLogo} />
</div>
)
});