React - 在上下文中更改状态而不重新渲染 DOM

React - Changing state in context not rerendering DOM

我有 useContext 将所有登录的用户保存在一个数组中。每个用户都有几个属性,其中之一是消息数组,它存储具有两个属性的对象。我通过组件内部的自定义挂钩使用此上下文,如下所示:const { loggedUsers, setLoggedUsers } = useUsers();。上下文如下所示:

export const UsersProvider = ({ children }: Props) => {
  const [loggedUsers, setLoggedUsers] = useState<any[]>([]);
  const socket = useSocket();

  const addUser = (user: any) => {
    console.log(typeof loggedUsers);
    const users: any[] = loggedUsers;
    users.push(user);
    setLoggedUsers(users);
  };

  const sortUsers = (users: any) => {
    users.forEach((user: any) => {
      user.self = user.userID === socket?.id;
    });

    let sorted = users.sort((a: any, b: any) => {
      if (a.self) return -1;
      if (b.self) return 1;
      if (a.username < b.username) return -1;
      return a.username > b.username ? 1 : 0;
    });
    setLoggedUsers(sorted);
  };

  return (
    <UsersContext.Provider
      value={{ loggedUsers, setLoggedUsers, addUser, sortUsers }}
    >
      {children}
    </UsersContext.Provider>
  );
};

数组中的用户如下所示:

{userID: 'Cm6vG0udcV6vl7MEAAAB', userName: 'test123', messages: [{message: 'dsada', fromSelf: true}], self: false, connected: true}

我正在像这样更新 context/state,但它不会强制重新呈现,因此不会显示用户之间的消息。可能是什么问题呢?如果我 console.log loggedUsers 消息在那里,但它们不会显示在 DOM 上。如果您需要更多代码,请告诉我。

socket.on('private message', listenerMessage);

const listenerMessage = async (msgInfo: any) => {
    console.log(msgInfo);
    console.log(msgInfo.from);
    const usersList = loggedUsers;
    for (let i = 0; i < usersList.length; i++) {
      const user = usersList[i];
      if (user.userID === msgInfo.from) {
        user.messages.push({
          message: msgInfo.message,
          fromSelf: false,
        });

        if (user !== state.userID) {
          user.hasNewMessages = true;
        }
        console.log(loggedUsers, 'onprivatemessage');
        setLoggedUsers(usersList);
        break;
      }
    }
  };

const onMessage = (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    if (state.userName) {
      socket?.emit('private-message', {
        message: mess,
        to: state.userID,
      });
      const usersList = loggedUsers;
      for (let i = 0; i < usersList.length; i++) {
        const user = usersList[i];
        if (user.userID === state.userID) {
          user.messages.push({ message: mess, fromSelf: true });
          console.log(loggedUsers, 'onmessage');
        }
      }
      setLoggedUsers(usersList);
    }

    setMess('');
  };

您在更新对象时使用了 const。 尝试使用 let 而不是 const。 const 对象不应更改。

你不应该直接改变 useState 的状态。 之前克隆它:

const usersList = [...loggedUsers]
const usersList = loggedUsers.slice()

这里:

setLoggedUsers(usersList);

您正在将相同的状态数组传递给 setLoggedUsers。克隆状态将解决这个问题。

你能做的是:

setLoggedUsers(prev=>{
        const prevUserList = prev.slice()
        //your for loop or anything
        return prevUserList;
});

也在这里:

  const usersList = loggedUsers;
  for (let i = 0; i < usersList.length; i++) {
    const user = usersList[i];
    if (user.userID === state.userID) {
      user.messages.push({ message: mess, fromSelf: true });
      console.log(loggedUsers, 'onmessage');
    }
  }

你从不更新 usersList ,我不知道这是否需要。