답변:
Tushar가 언급했듯이 채팅 하단에 더미 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 메서드를 사용하고 있습니다.
this.messagesEnd.scrollIntoView()
나를 위해 잘 작동했습니다. 사용할 필요가 없습니다 findDOMNode()
.
scrollToBottom(){this.scrollBottom.scrollIntoView({ behavior: 'smooth' })}
이 최신 버전에서 작동하도록
새 React.createRef()
메서드 와 일치하도록 답변을 업데이트하고 싶지만 기본적으로 동일 current
하며 생성 된 ref 의 속성을 염두에 두십시오 .
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>
)
}
}
최신 정보:
이제 후크를 사용할 수 있으므로 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={messagesEndRef} />
</div>
)
}
또한 https://codesandbox.io/s/scrolltobottomexample-f90lz 동작을 확인하려면 (매우 기본적인) 코드 샌드 박스를 만들었습니다.
this.messagesEnd.current
항상 존재합니다. 그럼에도 불구하고 this.messagesEnd.current
첫 번째 렌더링 전에 호출 하면 지적한 오류가 발생 한다는 점에 유의하는 것이 중요합니다 . Thnx.
this.messagesEnd
scrollTo 메서드의 첫 번째 예제에는 무엇이 있습니까?
useEffect
방법의 필요성에 배치합니다 () => {scrollToBottom()}
. 어쨌든 감사합니다
사용하지 마세요 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; }} />
}
}
import React, { useRef, useEffect } from 'react';
const MyComponent = () => {
const divRref = useRef(null);
useEffect(() => {
divRef.current.scrollIntoView({ behavior: 'smooth' });
});
return <div ref={divRef} />;
}
behavior
여야합니다 ( "편집은 6 자 이상이어야하기 때문에 편집 할 수 없음", 한숨).
scrollIntoView
with smooth
에 대한 지원 은 현재 매우 열악합니다.
@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();
}
참고:
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();
}
}
}
react-scrollable-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>
);
}
}
특정 height
또는max-height
면책 조항 : 나는 패키지의 소유자입니다.
메시지 컨테이너를 참조하십시오.
<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>
);
}
}
메시지 끝에 빈 요소를 만들고 해당 요소로 스크롤했습니다. 심판을 추적 할 필요가 없습니다.
React Hooks로 이것을하고 싶다면이 방법을 따를 수 있습니다. 더미 div의 경우 채팅 하단에 배치되었습니다. useRef 후크가 여기에 사용됩니다.
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>
);
}
내 ReactJS 버전 : 16.12.0
render()
함수 내부의 HTML 구조
render()
return(
<body>
<div ref="messageList">
<div>Message 1</div>
<div>Message 2</div>
<div>Message 3</div>
</div>
</body>
)
)
scrollToBottom()
요소의 참조를 얻을 함수. scrollIntoView()
기능 에 따라 스크롤 합니다.
scrollToBottom = () => {
const { messageList } = this.refs;
messageList.scrollIntoView({behavior: "smooth", block: "end", inline: "nearest"});
}
위의 함수를 내부에서 호출 componentDidMount()
하고componentDidUpdate()
에 대한 자세한 설명은 Element.scrollIntoView()
방문 developer.mozilla.org
작업 예 :
DOM scrollIntoView
메서드를 사용하여 구성 요소를 뷰에 표시 할 수 있습니다.
이를 위해 컴포넌트를 렌더링하는 동안 ref
속성을 사용하여 DOM 요소에 대한 참조 ID를 제공하십시오 . 그런 다음 라이프 사이클 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
은 전달 된 특정 채팅 메시지의 고유 ID입니다.props
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>
);
}
}
그의 좋은 답변에 대해 '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>
);
}
사용 React.createRef()
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>
)
}
}
다음은 TypeScript에서이 문제를 해결하는 방법입니다 (스크롤하는 대상 요소에 대한 참조 사용).
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>
}
React 및 Typescript와 함께 ref를 사용하는 방법에 대한 자세한 내용은 여기 에서 훌륭한 기사를 찾을 수 있습니다 .
정식 버전 (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>
)
}
}
Property 'scrollIntoView' does not exist on type 'RefObject<unknown>'.
및 Type 'HTMLDivElement | null' is not assignable to type 'RefObject<unknown>'. Type 'null' is not assignable to type 'RefObject<unknown>'.
그래서 ...