使用状态更新后状态不变

State not changing after update from use state

我是 React 新手。我正在尝试让我的套接字 io 侦听器工作。当我从 useEffect 出来时,它可以工作,但它被调用了几次。在 useEffect 中它只被调用一次(这显然很好)但是这次 users 没有更新 - 初始值。

function Users() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        getUsers();

        if(users.length > 0) {
            socket.on("statusChange", (data) => {
                console.log(users); // this returns initial state of users
                let tempUsers = [...users];
                let ndx = tempUsers.findIndex(obj => obj.id === data.id);
                if(ndx === -1)
                    return;

                tempUsers[ndx].status = data.status;
                setUsers(tempUsers);
            });
        }
    }, []);

    function getUsers() {
        fetch(/* stuff */)
        .then(res => res.json())
        .then(res => setUsers(res.data));
    }

    return (
        <div className={styles.container}>
            <div className={styles.usersContainer}>
                { users.map((user, i) => <UserCard key={i} user={user} />) }
            </div>
        </div>
    );
}

export default Users;

与其简单地执行 getUsers,不如将其与回调一起使用。然后在回调中执行 setUsers:

function Users() {
    const [users, setUsers] = useState([]);

    useEffect(() => {
        fetch(/* stuff */)
        .then(res => res.json())
        .then(res => {
          if(res.data.length > 0) {
            socket.on("statusChange", (data) => {
                console.log(res.data); // this returns initial state of users
                let tempUsers = [...res.data];
                let ndx = tempUsers.findIndex(obj => obj.id === data.id);
                if(ndx === -1)
                    return;

                tempUsers[ndx].status = data.status;
                setUsers(tempUsers);
            });
        }
        
        });
    }, []);


    return (
        <div className={styles.container}>
            <div className={styles.usersContainer}>
                { users.map((user, i) => <UserCard key={i} user={user} />) }
            </div>
        </div>
    );
}

export default Users;

我假设的部分内容:

  1. getUsers() 应该只调用一次:当组件挂载时
  2. 我们想收听 socket.on("statusChange") 并获取有关我们从 getUsers() 获得的用户的更新。
// This is pulled outside the component.
function getUsers() {
  fetch(/* stuff */)
  .then(res => res.json());
}

function Users() {
    const [users, setUsers] = useState([]);

    // Fetch users only once, when the component mounts.
    useEffect(() => {
      getUsers().then(res => {
        setUsers(res.data);
      });
    }, []);

    // Listen to changes
    useEffect(() => {
      if (!users.length) return;

      const listener = (data) => {
        // Functional update
        // See: https://reactjs.org/docs/hooks-reference.html#functional-updates
        setUsers(prevUsers => {
          let nextUsers = [...prevUsers];
          let ndx = nextUsers.findIndex(obj => obj.id === data.id);
          
          // What's up here? See below.
          if(ndx === -1) return nextUsers;

          nextUsers[ndx].status = data.status;
          return nextUsers;
        });
      };

      socket.on("statusChange", listener);

      // Unsubscribe when this component unmounts
      // See: https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1
      return () => socket.off("details", listener);
    }, [users]);

    return (
        <div className={styles.container}>
            <div className={styles.usersContainer}>
                { users.map((user, i) => <UserCard key={i} user={user} />) }
            </div>
        </div>
    );
}

export default Users;

关于if(ndx === -1) return nextUsers;

这意味着 users 的大小永远不会改变,即您不会处理有关新用户的数据。

或者,您可以 if(ndx === -1) return [ ...nextUsers, data ];