反应-为什么我分配scrollTop而元素没有得到这个?

时间:2019-08-29 09:29:15

标签: javascript reactjs

我建立了一个聊天室。我希望在组件加载时或收到新消息时可以滚动到底部。没有React,我尝试了,它就起作用了。使用React,我不会成功。

感谢帮助

我已经在JavaScript中尝试过并且可以正常工作,我已经在带有ref的React中进行过尝试,例如JavaScript中的代码。

const contentMsgElement = document.querySelector("#contentMsg");
contentMsgElement.scrollTop = contentMsgElement.scrollHeight;
import React from 'react';
import ReactDOM from 'react-dom';
import MessageChat from './message/messageChat';
import moment from 'moment';
import MessageDateHeader from './message/messageDateHeader';

class BodyChat extends React.Component
{
    constructor(props)
    {
        super(props);
        this.state = {
            socket:null,
            allMessages:[],
            dateNow:""
        };

        this.messageList = React.createRef();
    }

    componentDidMount()
    {
        const {socket,user} = this.props;

        this.setState({
            socket:socket,
            user:user
        },this.getLast10Msg);

        this.setState({
            dateNow:moment.utc().local().format("DD/MM/YY")
        });

        this.getNewMsg(socket);
    }

    componentDidUpdate(prevProps,prevState)
    {
        const prevAll = prevState.allMessages;
        const all = this.state.allMessages

        if(prevAll.length !== all.length)
        {
            if(this.messageList.current)
            {   
                const messageList = this.messageList.current;
                ReactDOM.findDOMNode(messageList).scrollTop = messageList.scrollHeight;
                console.dir(ReactDOM.findDOMNode(messageList));
            }
        }
    }


    getLast10Msg = () =>
    {
        const {socket} = this.state;

        socket.on("respGet10Msg",data => 
        {
            this.setState({
                allMessages:data
            });
        });
    }

  getNewMsg = socket =>
    {
        socket.on("respMsg",data => 
        {
            const newMsg = {
                userName:data.userName,
                MESSAGE:data.message,
                CODE_UTILISATEUR:data.userId,
                TIME:data.time,
                ID:(data.idMessage) ? "msg_" + data.idMessage : "tpm_" + data.idTpm
            };

            this.setState({
                allMessages:this.state.allMessages.concat(newMsg)
            });

            this.scrollToBottom();
        });
    }

    scrollToBottom = () =>
    {
        const contentMsg = this.messageList;
        console.log(contentMsg);
        contentMsg.scrollTop = contentMsg.scrollHeight;
    }
    msgDate = (time,displayDate) =>
    {
        const {dateNow} = this.state;
        const date = moment.utc(time).local().format("DD/MM/YY");
        const yesterday = moment.utc().local().subtract(1, 'days').format("DD/MM/YY");
        const currentDate = displayDate.date;
        const respDate = {...displayDate};

        if(date !== currentDate)
        {
            if(dateNow === date)
            {
                respDate.date = "Aujourd'hui";
            }
            else if(yesterday === date)
            {
                respDate.date = "Hier";
            }
            else
            {
                respDate.date = date;
            }
            respDate.display = true;
        }        
        else
        {
            respDate.display = false;
        }

        return respDate;
    }

    render()
    {
        const {allMessages,user} = this.state;
        let displayDate = {date:"",display:false};
        if(allMessages.length > 0)
        {
            const messages = allMessages.map(msg =>
            {
                const msgChat = <MessageChat 
                idMessage={msg.ID}
                userName={msg.userName}
                message={msg.MESSAGE}
                userId={msg.CODE_UTILISATEUR}
                time={msg.TIME}
                currentUser={user.CODE_UTILISATEUR}
                key={msg.ID}
                />;

                displayDate = this.msgDate(msg.TIME,displayDate);
                const msgDate = (displayDate.display) ? <MessageDateHeader date={displayDate.date}/> : "";
                return <React.Fragment>
                    {msgDate}
                    {msgChat}
                </React.Fragment>;
            }
            );

            return <div className="contentMsg" ref={this.messageList}>
                    {messages}
                    {("Aujourd'hui" !== displayDate.date) ? <MessageDateHeader date="Aujourd'hui"/> : ""}
                </div>;
        }
        else
        {
            return <div className="contentMsg">
                </div>;
        }
    }
}

export default BodyChat;
.contentMsg
    {
        display: grid;
        grid-gap: 0.2rem;
        overflow-y: auto;
        overflow-x: hidden;
    }

除了滚动聊天或在底部更新时滚动之外,我没有滚动!

@anik伊斯兰教Shojib

我尝试不工作

componentDidUpdate(prevProps,prevState)
    {
        

        if(this.messageList)
        {
            console.log("here");
            console.log(this.messageList.offsetTop);
            window.scrollTo({
                top:this.messageList.offsetTop,
                behavior: "smooth"  // Optional, adds animation
            })
            console.log(this.messageList.scrollTop);
        }

    }

3 个答案:

答案 0 :(得分:1)

在聊天屏幕底部放置一个不可见 div。 (在contentMsg内部。)

<div style={{display: none}} />

然后,在构造函数中定义一个ref

this.myRef = React.createRef()

将此ref附加到您不可见的div

<div style={{display: none}} ref={el => this.myRef = el} />

然后,每当您想滚动到底部(例如componentDidUpdate)时,请调用此函数:

this.myRef.scrollIntoView();

答案 1 :(得分:1)

我找到了解决方案。我不知道为什么渲染没有完成,然后才调用函数componentDidUpdate。所以我们第一次说渲染器已经更新并且可以使用。

我认为这是一个技巧,但是如果有人知道更好的解决方案。

componentDidUpdate(prevProps,prevState)
    {
        if(this.state.allMessages.length > 0 && prevState.allMessages.length !== this.state.allMessages.length)
        {
            this.setState({ changeHeight: true });
        }

        if(this.state.changeHeight && this.state.changeHeight !== prevState.changeHeight)
        {
            let height = ReactDOM.findDOMNode(this).scrollHeight;
            ReactDOM.findDOMNode(this).scrollTop = height;
            this.setState({ changeHeight: false });
        }
    }

答案 2 :(得分:0)

这里是react的滚动代码。该代码对我来说也适用

 componentDidUpdate(prevProps,prevState)
    {
        const prevAll = prevState.allMessages;
        const all = this.state.allMessages

        if(prevAll.length !== all.length)
        {
            if(this.messageList.current)
            {   
                window.scrollTo({
                    top:this.messageList.offsetTop,
                    behavior: "smooth"  // Optional, adds animation
                })
                console.dir(ReactDOM.findDOMNode(messageList));
            }
        }
    }

您可以像

一样使用ref
 return <div className="contentMsg" ref={(e) => this.messageList= e} >
                    {messages}
                    {("Aujourd'hui" !== displayDate.date) ? <MessageDateHeader 
                    date="Aujourd'hui"/> : ""}
                </div>;

这也应该起作用,但对我也不起作用

  ReactDOM.findDOMNode(messageList).scrollTop = messageList.scrollHeight;

您能尝试一件事吗?只能在componentDidUpdate的以下部分中运行

componentDidUpdate(prevProps,prevState)
    {


                window.scrollTo({
                    top:this.messageList.offsetTop,
                    behavior: "smooth"  // Optional, adds animation
                })

    } 

看看它是否有效,如果它起作用,则说明您的状况有问题