我想建立一个聊天系统,并自动滚动到底部时,进入窗口,当新的消息进来。如何在React中自动滚动到容器底部?


当前回答

这是Kent C. Dodds教授的useLayoutEffect的一个很好的用例。

https://kentcdodds.com/blog/useeffect-vs-uselayouteffect

如果你的效果正在改变DOM(通过一个DOM节点ref),并且DOM突变将改变DOM节点的外观,在它被呈现和你的效果改变它之间,那么你不想使用useEffect。

在我的情况下,我在一个div的底部动态生成元素,所以我必须添加一个小超时。

   const bottomRef = useRef<null | HTMLDivElement>(null);

    useLayoutEffect(() => {
        setTimeout(function () {
            if (bottomRef.current) bottomRef.current.scrollTop = bottomRef.current.scrollHeight;
        }, 10);
    }, [transactionsAmount]);

其他回答

我在消息的末尾创建了一个空元素,并滚动到该元素。不需要跟踪裁判。

感谢@enlitement

我们应该避免使用findDOMNode, 我们可以使用引用来跟踪组件

render() {
  ...

  return (
    <div>
      <div
        className="MessageList"
        ref={(div) => {
          this.messageList = div;
        }}
      >
        { messageListContent }
      </div>
    </div>
  );
}



scrollToBottom() {
  const scrollHeight = this.messageList.scrollHeight;
  const height = this.messageList.clientHeight;
  const maxScrollTop = scrollHeight - height;
  this.messageList.scrollTop = maxScrollTop > 0 ? maxScrollTop : 0;
}

componentDidUpdate() {
  this.scrollToBottom();
}

参考:

https://facebook.github.io/react/docs/react-dom.html#finddomnode https://www.pubnub.com/blog/2016-06-28-reactjs-chat-app-infinite-scroll-history-using-redux/

不使用findDOMNode

带有ref的类组件

class MyComponent extends Component {
  componentDidMount() {
    this.scrollToBottom();
  }

  componentDidUpdate() {
    this.scrollToBottom();
  }

  scrollToBottom() {
    this.el.scrollIntoView({ behavior: 'smooth' });
  }

  render() {
    return <div ref={el => { this.el = el; }} />
  }
}

带钩子的功能组件:

import React, { useRef, useEffect } from 'react';

const MyComponent = () => {
  const divRef = useRef(null);

  useEffect(() => {
    divRef.current.scrollIntoView({ behavior: 'smooth' });
  });

  return <div ref={divRef} />;
}

如果你想用React Hooks做到这一点,可以遵循这个方法。对于一个虚拟div已放置在聊天的底部。这里使用useRef Hook。

Hooks API参考:https://reactjs.org/docs/hooks-reference.html#useref

import React, { useEffect, useRef } from 'react';

const ChatView = ({ ...props }) => {
const el = useRef(null);

useEffect(() => {
    el.current.scrollIntoView({ block: 'end', behavior: 'smooth' });
});

 return (
   <div>
     <div className="MessageContainer" >
       <div className="MessagesList">
         {this.renderMessages()}
       </div>
       <div id={'el'} ref={el}>
       </div>
     </div>
    </div>
  );
}

如果用户已经在可滚动部分的底部,react- scrolable -feed会自动向下滚动到最新的元素。否则,它将使用户处于相同的位置。我认为这对聊天组件非常有用:)

我认为这里的其他答案将强制每次滚动,无论滚动条在哪里。scrollIntoView的另一个问题是,如果您的可滚动div不在视图中,它将滚动整个页面。

它可以这样使用:

import * as React from 'react'

import ScrollableFeed from 'react-scrollable-feed'

class App extends React.Component {
  render() {
    const messages = ['Item 1', 'Item 2'];

    return (
      <ScrollableFeed>
        {messages.map((message, i) => <div key={i}>{message}</div>)}
      </ScrollableFeed>
    );
  }
}

只要确保包装器组件具有特定的高度或max-height即可

免责声明:我是包裹的所有者