javascript 过滤器()是不起作用时,它的变量更新.如何修复它?

ivqmmu1c  于 2023-02-28  发布在  Java
关注(0)|答案(4)|浏览(134)

我正在创建一个聊天应用程序,其中消息变量是来自另一个组件.我想要到过滤器这消息根据他们的房间id
所以我用useEffect在每次消息更新时更新roomMessage变量。消息变量更新了,但是roomMessage没有更新,新消息也没有显示在屏幕上。是filter()函数的问题还是什么?

export default function Chat_body() {

///messages has all the message data
    let {userName,userID,messages} = useContext(AuthContext);

    const {roomID} = useParams();
    const [roomMessages,setRoomMessages] = useState(messages.filter((message) => message.room === parseInt(roomID)).reverse())

     useEffect(() => {
        
         setRoomMessages(messages.filter((message) => message.room === parseInt(roomID)).reverse())
         console.log(roomMessages)

       }, [roomID,messages]);

      

      
   

  return (
    <div className="chat_body">

        {roomMessages.map((message)=>{
            
            return(

                
                
      {roomMessages.map((message)=>{
            
            return(

                
                
        <div key={message.id} className={userName===message.sender ? "chat_message recieved" :"chat_message"}>
            <span className='avatar_span'><MdAccountCircle/></span>
            <div className={userName===message.sender ? "message chat_recieved" : "message"}>
                <span className='chat_name'>{message.sender}</span>
                <div className={userName===message.sender ? "sent_message  chat_reciever" : "sent_message"}>
                    <p>{message.message}</p>
                    <span className='timeSpan'>{message.sent_at}</span>
                </div>
            </div>
        </div>
                )

        })}
    )
}

context.js

import React,{createContext,useState,useEffect} from 'react'
import jwt_decode from "jwt-decode";
import { useNavigate } from 'react-router-dom';
import pusherJs from 'pusher-js';

const endpointMessage = 'http://127.0.0.1:8000/message'
 const [messages,setMessages] = useState([])


 useEffect(()=>{
     const pusher = new pusherJs('f12d9df33bdc80d7947b', {
      cluster: 'ap2'
    });

    var channel = pusher.subscribe('chat');
    channel.bind('message', function(data) {
      setMessages([...messages,data]);
      console.log(messages)
    });

    return ()=>{
      channel.unbind_all();
      channel.unsubscribe();
    }
  },[messages])

如果我Mapmessage变量,所有的消息都会显示出来,更新的消息也会呈现出来,但是当我试图过滤它们时,新消息却不会显示出来!

omvjsjqw

omvjsjqw1#

看起来问题出在你在useEffect钩子中更新roomMessages状态的方式上。当你调用setRoomMessages时,React不会立即更新状态,而是调度更新,并且出于性能原因,React会将多个更新一起批处理。这意味着当你在setRoomMessages之后立即调用console.log(roomMessages)时,你可能看不到roomMessages的更新值。
若要解决此问题,您可以使用useEffect挂钩以及roomID和messages依赖项,以便在其中任何一个发生更改时更新roomMessages状态:

useEffect(() => {
  const filteredMessages = messages.filter((message) => message.room === parseInt(roomID)).reverse();
  setRoomMessages(filteredMessages);
}, [roomID, messages]);

这将确保每当roomID或消息发生变化时,roomMessages总是更新为最新过滤的消息。
此外,请确保推送订阅中的消息状态被正确更新,而不是使用setMessages([... messages,data]),您应该使用函数更新语法来确保您正确更新状态:

setMessages((messages) => [...messages, data]);

这将确保您始终使用消息的最新值来更新状态。

更新

问题可能与您在useEffect挂接中更新roomMessages状态的方式有关。当您在React中更新状态时,更改可能不会立即反映在state变量中。相反,React会批处理状态更新并在稍后应用它们。这意味着如果您尝试在更新状态变量后立即访问它,则可能看不到更新后的值。
要确保使用roomMessages的更新值,可以使用setRoomMessages函数的回调版本。回调函数将接收当前状态值作为参数,因此可以使用它基于当前值更新状态。
下面是使用回调函数更新roomMessages的代码的更新版本:

export default function Chat_body() {
    const {userName,userID,messages} = useContext(AuthContext);
    const {roomID} = useParams();
    const [roomMessages, setRoomMessages] = useState([]);

    useEffect(() => {
        const filteredMessages = messages.filter(message => message.room === parseInt(roomID)).reverse();
        setRoomMessages(currentMessages => [...filteredMessages]);
    }, [roomID, messages]);

    return (
        <div className="chat_body">
            {roomMessages.map(message => (
                // display messages
            ))}
        </div>
    );
}

在这段代码中,我们在useEffect钩子的setRoomMessages调用中添加了一个回调函数,该回调函数接收当前状态值作为参数(currentMessages),并使用该值基于当前值更新状态,这确保了在更新状态值时,我们始终拥有最新的状态值。
注意,我们还将filter和reverse调用移到了setRoomMessages调用之外,因为不需要在每次渲染时创建新的filtered数组,而是在useEffect钩子中创建一次filtered数组,并使用它来更新状态。

7rfyedvj

7rfyedvj2#

useEffect(() => {
  setRoomMessages( prevMessage => {
    return prevMessage.filter(message => message.room === parseInt(roomID).reverse())
  })
  console.log(roomMessages)
}, [roomID,messages]);
b1zrtrql

b1zrtrql3#

只需从Chat_body组件中删除useStateuseEffect钩子,并直接从上下文中过滤messages(您还使用了两次map,这是不需要的)。

export default function Chat_body() {
  ///messages has all the message data
  let { userName, messages } = useContext(AuthContext);

  const { roomID } = useParams();

  const filteredMessages = messages.filter((message) => message.room === parseInt(roomID)).reverse();
  const isSender = userName === message.sender;

  return (
    <div className="chat_body">
      {filteredMessages.map((message) => (
        <div key={message.id} className={isSender ? 'chat_message recieved' : 'chat_message'}>
          <span className="avatar_span">
            <MdAccountCircle />
          </span>

          <div className={isSender ? 'message chat_recieved' : 'message'}>
            <span className="chat_name">{message.sender}</span>

            <div className={isSender ? 'sent_message  chat_reciever' : 'sent_message'}>
              <p>{message.message}</p>
              <span className="timeSpan">{message.sent_at}</span>
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}
ttcibm8c

ttcibm8c4#

我想明白了,问题是useParams收到的roomID的数据类型和message.room不一样,所以,每次我用message.room === roomID的条件进行过滤时,它都没有返回true。我必须用“==”使它成为prevMessage.filter(message => message.room == parseInt(roomID).reverse())才能工作。我非常抱歉给大家一个艰难的时间为这样愚蠢的错误,并感谢大家帮助我了。

相关问题