I’ve seen many questions about this but none that work for me. Basically, I have a GameScreen
component, where when the game starts, I want the URL path to change from "/roomcode/lobby" to "/roomcode/start".
const [roomCode, setRoomCode] = useState("");
const navigate = useNavigate();
useEffect(() => {
socket.on("game_has_started", (info) => {
navigate(`/${roomCode}/start`);
});
}, [socket]);
However, my page refreshes whenever the game starts, and thus the roomCode
state resets to ""
, and the page goes to "//start", which breaks the app. How can I stop roomCode
state from resetting when navigating?
edit: roomCode is 100% set to a non ""
value before the "game_has_started" event is emmitted.
3
Answers
The issue here is that you are using useState hook. Note that useState hooks are only available to a component. It’s like a local variable. So, when you navigate to a new component, it’s getting unmounted. And, that’s why it goes from ‘/roomcode/lobby’ to ‘//start’.
So, I suggest you to use localstorage to achieve your desired outcome which is persistence.
Hopefully that should solve the issue!
Issue
At a minimum you have a stale Javascript Closure issue in the
"game_has_started"
event handler.The initial
roomCode
state value""
is closed over in the"game_has_started"
event handler callback scope and won’t ever change/update until thesocket
dependency updates, in which case it will only re-enclose only the currentroomCode
state value at that moment in the lifecycle.Solution
Since the callback is pretty light you could likely get by with including the
roomCode
state in theuseEffect
hook’s dependency array, and return a cleanup function to remove the previous handler.Example:
If the callback needed to do substantially more work or you just don’t want to continually add/remove the handlers then an alternative is to cache the
roomCode
state into a React ref that can be mutated and referenced at any time in the component lifecycle.Example:
useNavigate offers an optional replace parameter. By default, this parameter is set to false, which performs a "push" navigation.
This creates a new history entry. If the user clicks the back button, they’ll navigate back to the previous page.
Setting replace to true will replace the current history entry instead of creating a new one.
This can be a way to prevent the page from appearing to reload because the user stays within the same history entry.