为什么状态不更新

时间:2020-11-04 21:36:46

标签: reactjs cookies use-effect use-state

新用户访问页面时,他们可以填写用户名,该用户名存储在状态和cookie中。稍后,我想访问该cookie并声明在游戏会话中的用户名,但是即使我知道它们已被设置(此时日志中会看到这些值,用户名也正确显示在标题中),此时它们都为空。为什么会这样?

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加载的用户名。

那么为什么它在这里显示为undefined? useState也是如此,它显示初始值(null),而不是实际值...

编辑:完整的代码在这里-https://github.com/faire2/loreHunters/blob/master/src/components/loginPage/LoginPage.js

该代码位于arnak-dev.herokuapp.com。

enter image description here

1 个答案:

答案 0 :(得分:1)

问题

  1. 回调中的陈旧附件以及放错效果的依赖项数组

    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
    });
    
  2. 从错误的渲染周期访问状态

    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);
    }
    

建议

我认为这些更改应该使您的代码更好,但是可能需要对依赖项和条件测试进行一些调整。

  1. 通过声明回调 outside 的效果来修复陈旧的附件。这里的想法是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);
    }, []);
    
  2. 通过“反应”状态更新来修复状态访问,该状态更新由被更新的状态变量作为依存关系触发的 触发的单独效果。

    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]);