Reactjs 如何在react中滚动到底部?
我想建立一个聊天系统,并在进入窗口和收到新消息时自动滚动到底部。如何在React中自动滚动到容器底部?您可以使用Reactjs 如何在react中滚动到底部?,reactjs,Reactjs,我想建立一个聊天系统,并在进入窗口和收到新消息时自动滚动到底部。如何在React中自动滚动到容器底部?您可以使用refs跟踪组件 如果您知道设置单个组件(最后一个)的ref,请发布 以下是我发现对我有用的东西: class ChatContainer extends React.Component { render() { const { messages } = this.props; var messageBubbles = messages.map
ref
s跟踪组件
如果您知道设置单个组件(最后一个)的ref
,请发布
以下是我发现对我有用的东西:
class ChatContainer extends React.Component {
render() {
const {
messages
} = this.props;
var messageBubbles = messages.map((message, idx) => (
<MessageBubble
key={message.id}
message={message.body}
ref={(ref) => this['_div' + idx] = ref}
/>
));
return (
<div>
{messageBubbles}
</div>
);
}
componentDidMount() {
this.handleResize();
// Scroll to the bottom on initialization
var len = this.props.messages.length - 1;
const node = ReactDOM.findDOMNode(this['_div' + len]);
if (node) {
node.scrollIntoView();
}
}
componentDidUpdate() {
// Scroll as new elements come along
var len = this.props.messages.length - 1;
const node = ReactDOM.findDOMNode(this['_div' + len]);
if (node) {
node.scrollIntoView();
}
}
}
类ChatContainer扩展React.Component{
render(){
常数{
信息
}=这是道具;
var messageBubbles=messages.map((message,idx)=>(
这个[''u div'+idx]=ref}
/>
));
返回(
{messageBubbles}
);
}
componentDidMount(){
这个.handleResize();
//初始化时滚动至底部
var len=this.props.messages.length-1;
const node=ReactDOM.findDOMNode(这个[''u div'+len]);
如果(节点){
scrollIntoView();
}
}
componentDidUpdate(){
//当新元素出现时滚动
var len=this.props.messages.length-1;
const node=ReactDOM.findDOMNode(这个[''u div'+len]);
如果(节点){
scrollIntoView();
}
}
}
我在消息末尾创建了一个空元素,并滚动到该元素。无需跟踪引用。正如Tushar提到的,您可以在聊天的底部保留一个虚拟div:
render(){
返回(
{this.renderMessages()}
{this.messagesEnd=el;}}>
);
}
然后在组件更新时滚动到它(即添加新消息时状态更新):
scrollToBottom=()=>{
this.messagesEnd.scrollIntoView({behavior:“smooth”});
}
componentDidMount(){
这个.scrollToBottom();
}
componentDidUpdate(){
这个.scrollToBottom();
}
我在这里使用的是标准方法。多亏了@enlitement
我们应该避免使用findDOMNode
,
我们可以使用refs
来跟踪组件
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();
}
render(){
...
返回(
{
this.messageList=div;
}}
>
{messageListContent}
);
}
scrollToBottom(){
const scrollHeight=this.messageList.scrollHeight;
const height=this.messageList.clientHeight;
const maxScrollTop=滚动高度-高度;
this.messageList.scrollTop=maxScrollTop>0?maxScrollTop:0;
}
componentDidUpdate(){
这个.scrollToBottom();
}
参考:
<div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>
componentDidMount
和componentDidUpdate
上调用上述方法
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
export default class StoryView extends Component {
constructor(props) {
super(props);
this.scrollToBottom = this.scrollToBottom.bind(this);
}
scrollToBottom = () => {
const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
};
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
render() {
return (
<div>
<Grid className="storyView">
<Row>
<div className="codeView">
<Col md={8} mdOffset={2}>
<div ref={(el) => { this.messagesContainer = el; }}
className="chat">
{
this.props.messages.map(function (message, i) {
return (
<div key={i}>
<div className="bubble" >
{message.body}
</div>
</div>
);
}, this)
}
</div>
</Col>
</div>
</Row>
</Grid>
</div>
);
}
}
导出默认类StoryView扩展组件{
建造师(道具){
超级(道具);
this.scrolltobttom=this.scrolltobttom.bind(this);
}
scrollToBottom=()=>{
const messagescocontainer=ReactDOM.findDOMNode(this.messagescocontainer);
messagesContainer.scrollTop=messagesContainer.scrollHeight;
};
componentDidMount(){
这个.scrollToBottom();
}
componentDidUpdate(){
这个.scrollToBottom();
}
render(){
返回(
{this.messagescocontainer=el;}}
className=“chat”>
{
this.props.messages.map(函数(message,i){
返回(
{message.body}
);
},本页)
}
);
}
}
作为另一个选项,它值得一看组件。我喜欢用下面的方法
componentDidUpdate(prevProps, prevState){
this.scrollToBottom();
}
scrollToBottom() {
const {thing} = this.refs;
thing.scrollTop = thing.scrollHeight - thing.clientHeight;
}
render(){
return(
<div ref={`thing`}>
<ManyThings things={}>
</div>
)
}
class ChatMessage extends Component {
scrollToBottom = (ref) => {
this.refs[ref].scrollIntoView({ behavior: "smooth" });
}
componentDidMount() {
this.scrollToBottom(this.props.message.MessageId);
}
render() {
return(
<div ref={this.props.message.MessageId}>
<div>Message content here...</div>
</div>
);
}
}
componentDidUpdate(prevProps,prevState){
这个.scrollToBottom();
}
scrollToBottom(){
const{thing}=this.refs;
thing.scrollTop=thing.scrollHeight-thing.clientHeight;
}
render(){
返回(
)
}
不要使用
使用ref对组件进行分类
类MyComponent扩展组件{
componentDidMount(){
这个.scrollToBottom();
}
componentDidUpdate(){
这个.scrollToBottom();
}
scrollToBottom(){
this.el.scrollIntoView({behavior:'smooth'});
}
render(){
返回{this.el=el;}}/>
}
}
带挂钩的功能组件:
import React,{useRef,useffect}来自“React”;
常量MyComponent=()=>{
const divRref=useRef(null);
useffect(()=>{
divRef.current.scrollIntoView({behavior:'smooth'});
});
返回;
}
工作示例:
可以使用DOM方法使组件在视图中可见
为此,在呈现组件时,只需使用ref
属性为DOM元素提供一个引用ID。然后运用生命周期的方法。我只是为这个解决方案提供了一个工作示例代码。以下是每次收到消息时呈现的组件。您应该编写用于呈现此组件的代码/方法
class ChatMessage extends Component {
scrollToBottom = (ref) => {
this.refs[ref].scrollIntoView({ behavior: "smooth" });
}
componentDidMount() {
this.scrollToBottom(this.props.message.MessageId);
}
render() {
return(
<div ref={this.props.message.MessageId}>
<div>Message content here...</div>
</div>
);
}
}
class-ChatMessage扩展组件{
scrollToBottom=(参考)=>{
this.refs[ref].scrollIntoView({behavior:“smooth”});
}
componentDidMount(){
this.scrolltobttom(this.props.message.MessageId);
}
render(){
返回(
Messag
import React, {Component} from 'react';
export default class ChatOutPut extends Component {
constructor(props) {
super(props);
this.state = {
messages: props.chatmessages
};
}
componentDidUpdate = (previousProps, previousState) => {
if (this.refs.chatoutput != null) {
this.refs.chatoutput.scrollTop = this.refs.chatoutput.scrollHeight;
}
}
renderMessage(data) {
return (
<div key={data.key}>
{data.message}
</div>
);
}
render() {
return (
<div ref='chatoutput' className={classes.chatoutputcontainer}>
{this.state.messages.map(this.renderMessage, this)}
</div>
);
}
}
class Messages extends React.Component {
const messagesEndRef = React.createRef()
componentDidMount () {
this.scrollToBottom()
}
componentDidUpdate () {
this.scrollToBottom()
}
scrollToBottom = () => {
this.messagesEnd.current.scrollIntoView({ behavior: 'smooth' })
}
render () {
const { messages } = this.props
return (
<div>
{messages.map(message => <Message key={message.id} {...message} />)}
<div ref={this.messagesEndRef} />
</div>
)
}
}
import React, { useEffect, useRef } from 'react'
const Messages = ({ messages }) => {
const messagesEndRef = useRef(null)
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" })
}
useEffect(() => {
scrollToBottom()
}, [messages]);
return (
<div>
{messages.map(message => <Message key={message.id} {...message} />)}
<div ref={messagesEndRef} />
</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>
);
}
}
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "end", inline: "nearest" });
}
scrollToTop = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" });
}
componentDidMount() {
this.scrollToBottom();
}
componentDidUpdate() {
this.scrollToBottom();
}
render () {
return (
<div>
<div className="MessageContainer" >
<div className="MessagesList">
{this.renderMessages()}
</div>
<div style={{ float:"left", clear: "both" }}
ref={(el) => { this.messagesEnd = el; }}>
</div>
</div>
</div>
);
}
window.scrollTo({
top: document.body.scrollHeight,
left: 0,
behavior: 'smooth'
});
render()
return(
<body>
<div ref="messageList">
<div>Message 1</div>
<div>Message 2</div>
<div>Message 3</div>
</div>
</body>
)
)
scrollToBottom = () => {
const { messageList } = this.refs;
messageList.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
}
import { useEffect, useRef } from 'react'
const messageRef = useRef();
useEffect(() => {
if (messageRef.current) {
messageRef.current.scrollIntoView(
{
behavior: 'smooth',
block: 'end',
inline: 'nearest'
})
}
})
useEffect(() => {
if (messageRef.current) {
messageRef.current.scrollIntoView(
{
behavior: 'smooth',
block: 'end',
inline: 'nearest'
})
}
},
[stateVariable])
return(
<body>
<div ref={messageRef}> // <= The only different is we are calling a variable here
<div>Message 1</div>
<div>Message 2</div>
<div>Message 3</div>
</div>
</body>
)
class MessageBox extends Component {
constructor(props) {
super(props)
this.boxRef = React.createRef()
}
scrollToBottom = () => {
this.boxRef.current.scrollTop = this.boxRef.current.scrollHeight
}
componentDidUpdate = () => {
this.scrollToBottom()
}
render() {
return (
<div ref={this.boxRef}></div>
)
}
}
class Chat extends Component <TextChatPropsType, TextChatStateType> {
private scrollTarget = React.createRef<HTMLDivElement>();
componentDidMount() {
this.scrollToBottom();//scroll to bottom on mount
}
componentDidUpdate() {
this.scrollToBottom();//scroll to bottom when new message was added
}
scrollToBottom = () => {
const node: HTMLDivElement | null = this.scrollTarget.current; //get the element via ref
if (node) { //current ref can be null, so we have to check
node.scrollIntoView({behavior: 'smooth'}); //scroll to the targeted element
}
};
render <div>
{message.map((m: Message) => <ChatMessage key={`chat--${m.id}`} message={m}/>}
<div ref={this.scrollTarget} data-explanation="This is where we scroll to"></div>
</div>
}
import {useEffect, useRef} from "react";
import React from "react";
import styled from "styled-components";
export interface Props {
children: Array<any> | any,
}
export function AutoScrollList(props: Props) {
const bottomRef: any = useRef();
const scrollToBottom = () => {
bottomRef.current.scrollIntoView({
behavior: "smooth",
block: "start",
});
};
useEffect(() => {
scrollToBottom()
}, [props.children])
return (
<Container {...props}>
<div key={'child'}>{props.children}</div>
<div key={'dummy'} ref={bottomRef}/>
</Container>
);
}
const Container = styled.div``;
scrollToBottom= async ()=>{
document.getElementById('bottomID').scrollIntoView();
}