Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

map() shows new messages from state only if I type something into input

Every time I send a message, map() only shows my new message when I type something in the input (re-render).

The listener works fine, it displays new messages in the console immediately after sending a new message, curiously, the messages state also updates when I look in React Developers Tools,

But useEffect[messages] does not trigger on a new message, and it only displays new messages after I type something in the input.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Here is my component with comments:

import { useState, useEffect, useRef } from "react";

const ChatWindowChannel = ({ window, chat }) => {
  const [messages, setMessages] = useState([]);
  const [message, setMessage] = useState("");
  const loaded = useRef(null);
  const messagesEndRef = useRef(null);

  const channelMessagesHandler = async () => {
    const channelMessagesListener = await chat.loadMessagesOfChannel(window);

    channelMessagesListener.on((msgs) => {

      console.log(msgs); // Here shows new messages after I click `send`
      // Works correct.

      setMessages(msgs); // In React Developers Tools the state `messages` are update if I click `send`
      // Works correct.

      console.log(messages); // Shows always empty array[]
      // Dont works correct 
    });
  };

  async function send() {
    await chat.sendMessageToChannel(window, message, {
      action: "join",
      alias: chat.gun.user().alias,
      pubKey: chat.gun.user().is.pub,
      name: "grizzly.crypto",
    });

    setMessage("");
  }

    useEffect(() => {
      // Shows only once. It shold every time on new message
      console.log("Messages changed");
    }, [messages]);

  useEffect(() => {
    loaded.current !== window.key && channelMessagesHandler();
    loaded.current = window.key;
  }, [window]);

  return (
    <div>
      <div className="ChatWindow">
        <h2>
          Channel {window.name} - {window.isPrivate ? "Private" : "Public"}
        </h2>

        <div>
          <details style={{ float: "right" }}>
            <summary>Actions</summary>
            <button
              onClick={async () => {
                await chat.leaveChannel(window);
              }}
            >
              Leave channel
            </button>
          </details>
        </div>

        <div className="msgs">
          {messages.map((message, key) => (
            <div key={`${key}-messages`}>
              <small>{message.time}</small>{" "}
              <small>{message.peerInfo.alias}</small> <p>{message.msg}</p>
              <div ref={messagesEndRef} />
            </div>
          ))}
        </div>

        <div>
          <div>
            <input
              type="text"
              value={message}
              onChange={(e) => setMessage(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter") send();
              }}
            />
          </div>
          <div>
            <button onClick={send}>Send</button>
          </div>
        </div>
      </div>
    </div>
  );
};

export default ChatWindowChannel;

>Solution :

Note 1: setMessages(msgs); do not change the value of messages immediately, it will be set only on next render so console.log(messages) just after setting will give you incorrect results.

Note 2: In case the reference of the array msgs that you are trying to set to a state variable is not changed even if array is modified – re-render will not be executed and useEffects will not be triggered, reference to an array needs to be new.

setMessages([...msgs]);

Same happens also with {objects}.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading