Подтвердить что ты не робот

Как прокручивать донизу в ответ?

Я хочу создать чат-систему и автоматически прокручивать ее донизу при входе в окно и при появлении новых сообщений. Как вы автоматически прокручиваете нижнюю часть контейнера в React?

4b9b3361

Ответ 1

Как упоминал Тушар, вы можете оставить фиктивный div внизу вашего чата:

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>
  );
}

а затем прокручивайте его, когда ваш компонент обновляется (т.е. состояние обновляется по мере добавления новых сообщений):

scrollToBottom = () => {
  this.messagesEnd.scrollIntoView({ behavior: "smooth" });
}

componentDidMount() {
  this.scrollToBottom();
}

componentDidUpdate() {
  this.scrollToBottom();
}

Я использую стандартный метод Element.scrollIntoView здесь.

Ответ 2

Не использовать findDOMNode

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

  componentDidUpdate() {
    this.scrollToBottom();
  }

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

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

Ответ 3

Я просто хочу, чтобы обновить ответ, чтобы соответствовать новому React.createRef() метод, но это в принципе то же самое, только имеет в виде current свойства в созданном иом:

class Messages extends React.Component {

  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>
    )
  }
}

ОБНОВИТЬ:

Теперь, когда хуки доступны, я обновляю ответ, чтобы добавить использование useRef и useEffect Реальная магия (метод React refs и метод scrollIntoView DOM) остается прежней:

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={this.messagesEndRef} />
    </div>
  )
}

Также сделал (очень простые) коды и ящик, если вы хотите проверить поведение https://codesandbox.io/s/scrolltobottomexample-f90lz

Ответ 4

Благодаря @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();
}

ссылка:

Ответ 5

Вы можете использовать ref для отслеживания компонентов.

Если вы знаете способ установки 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();
    }
  }
}

Ответ 6

Я создал пустой элемент в конце сообщений и прокручивал этот элемент. Нет необходимости отслеживать рефери.

Ответ 7

  • Ссылка на контейнер сообщений.

    <div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>
    
  • Найдите свой контейнер сообщений и сделайте его атрибут scrollTop равным scrollHeight:

    scrollToBottom = () => {
        const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer);
        messagesContainer.scrollTop = messagesContainer.scrollHeight;
    };
    
  • Вызвать выше метод на 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>
        );
    }
}

Ответ 8

Рабочий пример:

Вы можете использовать метод DOM scrollIntoView, чтобы сделать компонент видимым в представлении.

Для этого при рендеринге компонента просто укажите ссылочный идентификатор для элемента DOM с помощью атрибута ref. Затем используйте метод scrollIntoView на componentDidMount жизненный цикл. Я просто помещаю рабочий пример кода для этого решения. Ниже представлен компонент, каждый раз при получении сообщения. Вы должны написать код/​​методы для рендеринга этого компонента.

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>
        );
    }
}

Здесь this.props.message.MessageId - уникальный идентификатор конкретного сообщения чата, переданного как props

Ответ 9

прокручиваемая передача автоматически прокручивается до последнего элемента, если пользователь уже находится в нижней части прокручиваемой секции. В противном случае он оставит пользователя в том же положении. Я думаю, что это очень полезно для компонентов чата :)

Я думаю, что другие ответы здесь заставят прокручивать каждый раз независимо от того, где была полоса прокрутки. Другая проблема с 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>
    );
  }
}

Просто убедитесь, что есть оберточный компонент с определенной height или max-height

Отказ от ответственности: я являюсь владельцем пакета

Ответ 11

Мне нравится делать это следующим образом.

componentDidUpdate(prevProps, prevState){
  this.scrollToBottom();
}

scrollToBottom() {
  const {thing} = this.refs;
  thing.scrollTop = thing.scrollHeight - thing.clientHeight;
}

render(){
  return(
    <div ref={`thing`}>
      <ManyThings things={}>
    </div>
  )
}

Ответ 12

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>
        );
    }
}

Ответ 13

Полная версия (Typescript):

import * as React from 'react'

export class DivWithScrollHere extends React.Component<any, any> {

  loading:any = React.createRef();

  componentDidMount() {
    this.loading.scrollIntoView(false);
  }

  render() {

    return (
      <div ref={e => { this.loading = e; }}> <LoadingTile /> </div>
    )
  }
}

Ответ 14

спасибо 'metakermit' за хороший ответ, но я думаю, что мы можем сделать его немного лучше, для прокрутки вниз, мы должны использовать это:

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>
  );
}

Ответ 15

Если вы хотите сделать это с помощью React Hooks, этот метод можно использовать. Для фиктивного div был размещен в нижней части чата. useRef Hook используется здесь.

Справочник по 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>
  );
}

Ответ 16

****Can anyone please let me know why its not working****
<div>
   <Row>
      <Col >
      <div className="CONTAINER">
         <A FUNCTIONAL COMPONENT />
         <div style={{ float:"left", clear: "both" }} ref={(el) => { this.messagesEnd = el; }}>
      </div>
</div>
</Col>
<Col >
<A FUNCTIONAL COMPONENT />
</Col>
</Row>
</div>
scrollToBottom = () => {
this.messagesEnd.scrollIntoView({ behavior: "smooth" });
}
componentDidUpdate() {
this.scrollToBottom(true);
}