Массив состояний React JS пуст внутри функции, но элементы отображаются при рендеринге

#javascript #reactjs

#javascript #reactjs

Вопрос:

Я пишу этот компонент react для рендеринга всех чатов пользователя в приложении для чата. Список диалогов извлекается из конечной точки REST и устанавливается как переменная состояния. Когда новое сообщение поступает через сокет, я пытаюсь вывести диалог в списке в начало и пометить его другим цветом.

Код для этого выглядит следующим образом:

 const [conversationsList, setConversationsList] = useState([]);

//When a new message arrives, 
const markNewConversation = (message) => {
  console.log(conversationsList); //Empty array
  let newConversationList = conversationsList.map((conversationElement) => {
    if (conversationElement.thread_id === message.thread_id) {
      conversationElement.date_created = message.date_created;
      conversationElement.new_for.push(user._id);
    }
    return conversationElement;
  });
  console.log(newConversationList);
  newConversationList = newConversationList.sortBy(function (o) {
    return o.date_created;
  });
  console.log(newConversationList); //Empty as well.
  setConversationsList(newConversationList); //Whole screen goes black on this.
};

useEffect(() => {
    if (user._id === null) history.push("/");
    connectSocket();
    socket.on("_messageIn", markNewConversation);
    getThreads().then((threads) => {
      threads.forEach((thread, index) => {
        let allParticipants = thread.thread_participants;
        threads[index].other_user = allParticipants.find((participant) => {
          return participant._id != user._id;
        });
      });
      setConversationsList(threads);
      setIsLoading(false);
    });
    // returned function will be called on component unmount
    return () => {
      socket.off("_messageIn", markNewConversation);
    };
  }, []);

return conversationsList.map((conversation) => {
 return(//magically appears inside this div.)
})
  

Проблема в том, что когда приходит новое сообщение, функция получает пустой массив, и весь экран становится пустым. Я даже не устанавливаю для массива значение пустой в любом месте. Где я ошибаюсь?

Комментарии:

1. Что это //magically appears inside this div. ? Как на самом деле выглядит этот возврат.

2. @DamianM я отображаю имена всех людей в разговоре в виде списка внутри возврата карты. И имена фактически отображаются в пользовательском интерфейсе. Но точно такой же массив состояний пуст внутри функции.

Ответ №1:

В этой функции вы изменяете объекты, это может вызвать странные ошибки.

 let newConversationList = conversationsList.map((conversationElement) => {
if (conversationElement.thread_id === message.thread_id) {
  conversationElement.date_created = message.date_created;
  conversationElement.new_for.push(user._id);
}
return conversationElement;
  

});

это должно выглядеть так:

 let newConversationList = conversationsList.map((conversationElement) =>
     (conversationElement.thread_id === message.thread_id) ? {
         ...conversationElement, 
         date_created: message.date_created,
         new_for: [...conversationElement.new_for, user.id]
    } : { 
        ...conversationElement, 
        new_for: [...conversationElement.new_for]
    }
  

Комментарии:

1. Массив, даже до ввода этой функции отображения, пуст. Как вы можете видеть в первой строке markNewConversation функции.

Ответ №2:

В javascript существует концепция изменения состояния, и мы никогда не должны изменять объекты напрямую. Здесь вы допускаете ошибку в том, что при поступлении нового сообщения он заменяет весь объект новым и как бы повторно инициализирует его. Поэтому распределите состояние с помощью оператора распространения перед добавлением нового сообщения. Сделайте так:

  let newConversationList = conversationsList.map((conversationElement) =>
     (conversationElement.thread_id === message.thread_id) ? {
         ...conversationElement, //spread/copy like this before mutating
         date_created: message.date_created,
         new_for: [...conversationElement.new_for, user.id]
    } : { 
        ...conversationElement, //spread/copy like this before mutating
        new_for: [...conversationElement.new_for]
    }
  

Комментарии:

1. Массив, даже до ввода этой функции отображения, пуст. Как вы можете видеть в первой строке markNewConversation функции.

2. Да, он может быть пустым при запуске, но во время выполнения он добавляет и изменяет предыдущий, когда мы играем с приложением, поэтому избегайте их прямого изменения, не создавая его копию.

3. К сожалению, изменение таким образом также не сработало..