Reactjs 为什么状态不更新
当新用户访问页面时,他们可以填写用户名,该用户名存储在state和cookie中。稍后,我想访问cookie和state来标识游戏会话中的用户名,但是在那一点上它们都是空的,即使我知道它们已经设置好了(日志记录可以看到值,用户名正确地显示在标题中)。为什么会这样Reactjs 为什么状态不更新,reactjs,cookies,use-effect,use-state,Reactjs,Cookies,Use Effect,Use State,当新用户访问页面时,他们可以填写用户名,该用户名存储在state和cookie中。稍后,我想访问cookie和state来标识游戏会话中的用户名,但是在那一点上它们都是空的,即使我知道它们已经设置好了(日志记录可以看到值,用户名正确地显示在标题中)。为什么会这样 const [cookies, setCookie] = useCookies(["username"]); const [formerUsername, setFormerUsername] = useState(
const [cookies, setCookie] = useCookies(["username"]);
const [formerUsername, setFormerUsername] = useState(cookies.username ? cookies.username : null);
...
function handleUsernameChange(username) {
setCookie("username", username, {path: "/", expires: expirationDate});
setFormerUsername(username);
...
}
useEffect(() => {
...
socket.on(TRANSMISSIONS.startGame, data => {
let playerIndex = data.room.players.indexOf(cookies.username);
history.push({pathname: "/game", data: {username: cookies.username, room: data.room, playerIndex: playerIndex,
}});
});
播放器索引为-1,因为cookies.username未定义。我知道它是设置的,因为我a)看到cookie,b)在页面标题中看到从cookie加载的用户名
那么为什么在这里显示为未定义?useState也是如此,它显示初始值(null
),而不是实际值
编辑:完整代码在此处-
代码在arnak-dev.herokuapp.com上直播
问题
useEffect(() => {
// extend cookie if it exists
...
socket.on(TRANSMISSIONS.startGame, data => {
let playerIndex = data.room.players.indexOf(cookies.username);
history.push({
pathname: "/game",
data: {
username: cookies.username, // <-- value when effect ran
room: data.room,
playerIndex: playerIndex,
},
});
});
...
socket.on(TRANSMISSIONS.currentUsersAndData, data => {
console.log("received actual room and users data");
if (!shakedHand) { // <-- stale
setShakedHand(true)
}
setUsers(data.users);
setRooms(data.rooms);
setRoomIsFull(false);
}, []) // <-- dependency array
});
function handleUsernameChange(username) {
setCookie("username", username, {path: "/", expires: expirationDate});
setFormerUsername(username);
setShowCreateUsername(false);
}
...
useEffect(() => {
if (!formerUsername) {
socket.emit(TRANSMISSIONS.handShake, cookies.username);
} else {
socket.emit(
TRANSMISSIONS.usernameChanged,
{
formerUsername: formerUsername,
newUsername: username,
},
);
}
}, [cookies, formerUsername, username]);
“当一个新用户访问页面时,他可以填写用户名”-如果你的访问者是女性怎么办?如果你使用一个特效来简单地记录对
cookies
的更改,你会在你的组件中看到它的更新吗?您能提供一个更完整的组件示例吗?socket
的作用是什么?我怀疑您已经关闭了startName
回调中的cookies
值。cookies.username
在useState(cookies.username?cookies.username:null)时尚未定义代码>,并且您的useffect
仅在安装组件时运行一次。当cookies
状态更新时,您无法更新任何套接字详细信息。对,我认为您有一些问题。首先,是的,由于useffect
有一个空的依赖项数组,您似乎已经关闭了socket
事件处理程序中的初始cookies
状态。其次,在一些函数中调用setCookie
,但随后一两行会发出当前的cookie.username
值(而不是刚刚排队等待下一个渲染周期的值)。第三,(我猜与第一个相关)您的效果不会返回清理功能(a)断开/关闭任何打开的套接字,以及(B)重新关闭事件处理程序中更新的cookies
状态值。套接字需要保持打开状态,直到您导航到新路由,或者至少,注销登录页组件添加的事件处理程序。这可能是您想要的带有返回清理函数的挂载效果。我认为要解决cookies
值的主要问题,需要定义依赖于effect hook外部的cookies
的套接字回调。如果您愿意,我可以提供一个示例作为答案。我已经实现了您提供的两个更改,但仍然发生相同的错误。我已将您的更改推送到回购协议中,以便您可以查看它们,您还可以查看现场的情况。我更不了解的是,if(cookies.username&&!shakedHand)
useEffect的一部分立即注册新的cookie。我真是太傻了。@Faire我在heroku上玩过你的应用程序,它在游戏开始前似乎一直有效,但我在黑暗中跌跌撞撞。我看到formerUsername
状态更新到我的用户名、cookies集。我想我看到shaked和状态没有更新。你能提供复制步骤吗?复制是100%:1。不存在cookie。2.创建新用户名。3.不刷新创建一个新游戏并启动它。它将崩溃,因为它将无法确定用户。但似乎传输总是触发页面初始化时创建的useState效果。我更改了代码,以便通过日志显式地将用户名传递给startGame函数。我看到用户名被正确地传递到函数(调试器显示useEffect知道新用户名),但是一旦它到达StartName函数,用户名就会再次被取消定义。日志显示StartName函数实际上运行了两次-首先使用未定义的用户名,然后(太晚)使用已定义的用户名。
const onStartGameHandler = data => {
const playerIndex = data.room.players.indexOf(cookies.username);
history.push({
pathname: "/game",
data: {
username: cookies.username,
room: data.room,
playerIndex: playerIndex,
},
});
};
const onUsersAndDataHandler = data => {
console.log("received actual room and users data");
if (!shakedHand) {
setShakedHand(true)
}
setUsers(data.users);
setRooms(data.rooms);
setRoomIsFull(false);
}
useEffect(() => {
// extend cookie if it exists
if (cookies.username && !shakedHand) { ...
...
socket.on(TRANSMISSIONS.startGame, onStartGameHandler);
...
socket.on(TRANSMISSIONS.currentUsersAndData, onUsersAndDataHandler);
// return clean up function
return () => socket.off(TRANSMISSIONS.startGame);
}, []);
function handleUsernameChange(username) {
setCookie("username", username, {path: "/", expires: expirationDate});
setFormerUsername(username);
setShowCreateUsername(false);
}
...
useEffect(() => {
if (!formerUsername) {
socket.emit(TRANSMISSIONS.handShake, cookies.username);
} else {
socket.emit(
TRANSMISSIONS.usernameChanged,
{
formerUsername: formerUsername,
newUsername: username,
},
);
}
}, [cookies, formerUsername, username]);