React中Link的onClick设置props在History组件中为undefined的问题
prePassword Prop is Undefined in History Component After Clicking Link Let's break down why this is happening and walk through actionable fixes:
The Root Cause
React's useState updates are asynchronous. When you click the Link in your Item component, two actions fire almost simultaneously:
- You call
setPropsPassword(password)to update thepasswordstate in the parentStorecomponent. - The
Linktriggers an immediate route change to/history/:id.
Since state updates don't take effect instantly, the History component mounts before the password state finishes updating. That's why it receives the initial undefined value as prePassword.
Your other working Link in the Item component probably doesn't trigger a cross-route navigation—so the component re-renders naturally after the state update completes, allowing it to pick up the new password value.
Fix Options
Option 1: Use useNavigate to Delay Navigation Until State Updates
Instead of relying on Link, use React Router's useNavigate hook to explicitly navigate only after the state update has a chance to apply. We'll use useEffect to listen for state changes:
- Update your
Itemcomponent:import { useNavigate } from 'react-router-dom'; import { useEffect, useState } from 'react'; export function Item({ id, prePassword, updateList, setPropsPassword }) { const navigate = useNavigate(); const [shouldNavigate, setShouldNavigate] = useState(false); const handleOpenHistory = () => { setPropsPassword(password); setShouldNavigate(true); }; // Navigate only once the password state has updated useEffect(() => { if (shouldNavigate) { navigate(`/history/${id}`); setShouldNavigate(false); } }, [shouldNavigate, navigate, id]); // Replace Link with a button (or keep Link and prevent default behavior) return ( <button onClick={handleOpenHistory} className="btn-open-history float-left btn btn-primary"> Geschiedenis </button> ); }
Option 2: Pass Password as a Route Query Parameter
If the password isn't sensitive, attach it directly to the URL as a query parameter. This lets the History component retrieve it from the route, eliminating the need to rely on parent state:
Update the
LinkinItem:<Link to={`/history/${id}?password=${encodeURIComponent(password)}`} className="btn-open-history float-left btn btn-primary" > Geschiedenis </Link>Modify your
Historycomponent to read the query parameter. Since it's a class component, wrap it withwithRouterto access thelocationprop:import { withRouter } from 'react-router-dom'; class History extends React.Component { componentDidMount() { const searchParams = new URLSearchParams(this.props.location.search); const password = searchParams.get('password'); console.log('Password from route:', password); // You can store this in component state if needed } render() { return (...) } } export default withRouter(History);
Option 3: Guard History Render Until password is Available
In your parent Store component, add a check for password before rendering History. This ensures the component only mounts once the state has been updated:
{props.match.path=="/history/:id" && id && password && <History prePassword={password} id={id} key="item" />}
Note: This will prevent History from rendering if password is undefined, so only use this if that aligns with your business logic.
内容的提问来源于stack exchange,提问作者TimeParadox

