为什么状态不更新
Why does the state not update
当新用户访问页面时,他们可以填写用户名,该用户名存储在 state 和 cookie 中。我稍后想访问该 cookie 和状态以在游戏 session 中识别用户名,但此时它们都是空的,即使我知道它们已被设置(日志记录看到值,用户名正确显示在header)。为什么会这样?
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) 在页面的 header 中看到了从 cookie 加载的用户名。
那为什么这里显示为undefined呢? useState 也是如此,它显示初始值 (null
),而不是实际值...
编辑:完整代码在这里 - https://github.com/faire2/loreHunters/blob/master/src/components/loginPage/LoginPage.js
代码在 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);
if (!formerUsername) { // <-- current formerUsername state
socket.emit(
TRANSMISSIONS.handShake,
cookies.username, // <-- current cookies state
);
} else {
socket.emit(
TRANSMISSIONS.usernameChanged,
{
formerUsername: formerUsername, // <-- current formerUsername state
newUsername: username, // <-- current username state
},
);
}
setShowCreateUsername(false);
}
建议
我认为这些更改应该能让您的代码变得更好,但可能需要对依赖项和条件测试进行一些调整。
通过在 效果之外声明回调来修复陈旧的外壳。这里的想法是 onStartGameHandler
定义每个渲染周期并包含当前状态。
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]);
当新用户访问页面时,他们可以填写用户名,该用户名存储在 state 和 cookie 中。我稍后想访问该 cookie 和状态以在游戏 session 中识别用户名,但此时它们都是空的,即使我知道它们已被设置(日志记录看到值,用户名正确显示在header)。为什么会这样?
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) 在页面的 header 中看到了从 cookie 加载的用户名。
那为什么这里显示为undefined呢? useState 也是如此,它显示初始值 (null
),而不是实际值...
编辑:完整代码在这里 - https://github.com/faire2/loreHunters/blob/master/src/components/loginPage/LoginPage.js
代码在 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); if (!formerUsername) { // <-- current formerUsername state socket.emit( TRANSMISSIONS.handShake, cookies.username, // <-- current cookies state ); } else { socket.emit( TRANSMISSIONS.usernameChanged, { formerUsername: formerUsername, // <-- current formerUsername state newUsername: username, // <-- current username state }, ); } setShowCreateUsername(false); }
建议
我认为这些更改应该能让您的代码变得更好,但可能需要对依赖项和条件测试进行一些调整。
通过在 效果之外声明回调来修复陈旧的外壳。这里的想法是
onStartGameHandler
定义每个渲染周期并包含当前状态。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]);