简体   繁体   中英

React (Next) won't re-render after redux state change (yes, state returned as new object)

I am facing a problem with re-rendering after a state change in my NextJS app.

The function sendMessageForm launches a redux action sendMessage which adds the message to the state.
The problem is unrelated to the returned state in the reducer as I am returning a new object( return {...state} ) which should trigger the re-render!

Is there anything that might block the re-render?
This is the file that calls & displays the state, so no other file should be responsible, But if you believe the problem might lie somewhere else, please do mention !

import { AttachFile, InsertEmoticon, Mic, MoreVert } from '@mui/icons-material';
import { Avatar, CircularProgress, IconButton } from '@mui/material';
import InfiniteScroll from 'react-infinite-scroller';
import Head from 'next/head';
import { useState, useEffect } from 'react';
import Message from '../../components/Message.component';
import styles from '../../styles/Chat.module.css'
import { useRouter } from 'next/router'
import {useSelector, useDispatch} from "react-redux"
import {bindActionCreators} from "redux"
import * as chatActions from "../../state/action-creators/chatActions"

const Chat = () => {
  const router = useRouter()
  const { roomId } = router.query

  const auth = useSelector((state)=> state.auth)
  const messages = useSelector((state)=> state.chat[roomId].messages)

  const dispatch = useDispatch()
  const {getMessages, markAsRead, sendMessage} = bindActionCreators(chatActions, dispatch)

  const [inputValue, setInputValue] = useState("")
  

  const sendMessageForm = (e) => {
      e.preventDefault()
      console.log("***inputValue:", inputValue)

      sendMessage(roomId, inputValue)
  }

  const loadMessages = (page) => {
      if(roomId)
        getMessages(roomId, page)
  }

  //user-read-message
  useEffect(() => {
    //user-read-message
    markAsRead(roomId, auth.user._id)
  }, [messages]);

  return (
    <div className={styles.container}>
        <Head>
            <title>Chat</title>
        </Head>

        <div className={styles.header}>
            <Avatar/>
            <div className={styles.headerInformation}>
                <h3>Zabre el Ayr</h3>
                <p>Last Seen ...</p>
            </div>
            <div className={styles.headerIcons}>
                <IconButton>
                    <AttachFile/>
                </IconButton>

                <IconButton>
                    <MoreVert/>
                </IconButton>
            </div>
        </div>

        <div className={styles.chatContainer}>
            <InfiniteScroll
                isReverse={true}
                pageStart={0}
                loadMore={loadMessages}
                hasMore={messages.hasNextPage || false}
                loader={<div className={styles.loader} key={0}><CircularProgress /></div>}
            >
                {Object.keys(messages.docs).map((key, index)=>{
                return<Message
                    key={index}
                    sentByMe={messages.docs[key].createdBy === auth.user._id}
                    message={messages.docs[key].msg}
                />})}
            </InfiniteScroll>
            <span className={styles.chatContainerEnd}></span>
        </div>

        <form className={styles.inputContainer}>
            <InsertEmoticon/>
            <input className={styles.chatInput} value={inputValue} onChange={(e)=>setInputValue(e.target.value)}/>
            <button hidden disabled={!inputValue} type='submit' onClick={sendMessageForm}></button>
            <Mic/>
        </form>
    </div>)
};

export default Chat;

useSelector requires a new object with a new reference from the object you are passing to it in order to trigger the re-render

What you're doing with return {...state} is just creating a new object for the parent object but not the nested one useSelector is using, which is in your case:

const messages = useSelector((state)=> state.chat[roomId].messages)

So, you should return the whole state as a new object WITH a new state.chat[roomId].messages object

In other words, the references for the root object & the one being used should be changed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM