어떻게 반응해서 아래로 스크롤합니까?
채팅 시스템을 구축하여 창으로 들어가거나 새로운 메시지가 들어오면 자동으로 아래로 스크롤하고 싶습니다.React에서 용기의 맨 아래로 자동 스크롤하려면 어떻게 해야 합니까?
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 메서드를 사용하고 있습니다.
나는 단지 새로운 것에 맞춰 답을 업데이트하고 싶다.React.createRef()
방법은 같지만 기본적으로는 동일합니다.current
다음 중 하나:
class Messages extends React.Component {
const messagesEndRef = React.createRef()
componentDidMount () {
this.scrollToBottom()
}
componentDidUpdate () {
this.scrollToBottom()
}
scrollToBottom = () => {
this.messagesEndRef.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" (React refs)scrollIntoView
DOM 식은 은은 dom dom dom dom 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
사용 안 함
참조가 있는 클래스 구성 요소
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} />;
}
@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();
}
참조:
- 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/
제가 추천하고 싶은 가장 쉽고 좋은 방법은요.
My React JS 버전: 16.12.0
클래스 컴포넌트의 경우
내부 HTML 구조render()
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"});
}
위의 를 의의함 and의함 inside inside inside inside and and inside inside 。componentDidMount()
★★★★★★★★★★★★★★★★★」componentDidUpdate()
기능 컴포넌트(훅)의 경우
★★★useRef()
★★★★★★★★★★★★★★★★★」useEffect()
import { useEffect, useRef } from 'react'
함수 내(「」를 useState()
)
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])
그리고 마지막으로 HTML 구조
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>
)
은, 을 참조해 주세요.Element.scrollIntoView()
developer.mozilla.org를 방문하다
콜백 레퍼런스의 자세한 내용은 reactjs.org를 참조하십시오.
사용자가 이미 스크롤 가능한 섹션의 맨 아래에 있는 경우 react-controllable-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
면책사항:나는 그 소포의 주인이다.
작업에 대한 아래 답변은 얻을 수 없었지만 단순 js는 나를 위해 성공했습니다.
window.scrollTo({
top: document.body.scrollHeight,
left: 0,
behavior: 'smooth'
});
리액트 훅을 사용하여 이 작업을 수행할 경우 이 방법을 따를 수 있습니다.더미 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>
);
}
상위 답변의 crollIntoView(...) 접근 방식에는 두 가지 주요 문제가 있습니다.
부모 요소가 창 경계 밖으로 스크롤되면 페이지 전체가 스크롤되므로 의미론적으로 올바르지 않습니다.브라우저는 문자 그대로 요소를 표시하기 위해 필요한 모든 것을 스크롤합니다.
useEffect()를 사용하는 기능 컴포넌트에서는 적어도 Chrome 96.0.4665.45에서는 신뢰할 수 없는 결과를 얻을 수 있습니다.useEffect()는 페이지 새로고침 시 너무 빨리 호출되어 스크롤이 실행되지 않습니다.setTimeout(... 0)을 사용하여 스크롤IntoView를 지연시키면 페이지 새로고침이 수정되지만 적어도 나에게는 새로고침 탭에 처음 로드되지 않습니다.
다음은 제가 사용하고 있는 솔루션입니다.솔루션의 견고성과 오래된 브라우저와의 호환성이 향상되었습니다.
function Chat() {
const chatParent = useRef<HTMLDivElement(null);
useEffect(() => {
const domNode = chatParent.current;
if (domNode) {
domNode.scrollTop = domNode.scrollHeight;
}
})
return (
<div ref={chatParent}>
...
</div>
)
}
하시면 됩니다.ref
컴포넌트를 추적합니다.
「 」를하는 있는 .ref
컴포넌트( 컴포넌트투고해 !1개의 개별 컴포넌트(마지막 컴포넌트)를 투고해 주세요!
나에게 효과가 있다는 것을 알게 된 것은 다음과 같습니다.
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();
}
}
}
메시지 컨테이너를 참조합니다.
<div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>
메시지 컨테이너를 .
scrollTop
equal " " " "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>
);
}
}
메시지 끝에 빈 요소를 만들고 해당 요소로 스크롤했습니다.레퍼런스를 추적할 필요가 없습니다.
작업 예:
DOM 방법을 사용하여 구성요소를 보기에 표시할 수 있습니다.
위해 때를 DOM ID를 하여 지정하기만 하면 .ref
기여하다.그런 다음 라이프 사이클에 따라 방법을 사용합니다.이 솔루션의 샘플 코드를 입력했을 뿐입니다.다음은 메시지가 수신될 때마다 표시되는 구성 요소 렌더링입니다.이 구성 요소를 렌더링하기 위한 코드/메서드를 작성해야 합니다.
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>
);
}
또 다른 옵션으로 리액트 스크롤 컴포넌트를 검토할 필요가 있습니다.
나는 그것을 다음과 같이 하는 것을 좋아한다.
componentDidUpdate(prevProps, prevState){
this.scrollToBottom();
}
scrollToBottom() {
const {thing} = this.refs;
thing.scrollTop = thing.scrollHeight - thing.clientHeight;
}
render(){
return(
<div ref={`thing`}>
<ManyThings things={}>
</div>
)
}
TypeScript에서 이 문제를 해결하는 방법은 다음과 같습니다(ref를 사용하여 스크롤하는 대상 요소에 대한 참조 사용).
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>
}
Ref를 React 및 Typescript와 함께 사용하는 방법에 대한 자세한 내용은 여기를 참조하십시오.
난 이거면 돼
messagesEndRef.current.scrollTop = messagesEndRef.current.scrollHeight
여기서 const messagesEndRef = useRef(); 사용
사용.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>
)
}
}
이는 위의 답변에서 데이터 배열이 아닌 '자녀'를 지원하도록 수정되었습니다.
주의: 스타일 컴포넌트의 사용은 솔루션에서 중요하지 않습니다.
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``;
페이지 하단으로 스크롤하려면 먼저 페이지 하부에 있는 ID를 선택해야 합니다.그런 다음 document.getElementById를 사용하여 ID를 선택하고 ScrollIntoView()를 사용하여 아래로 스크롤할 수 있습니다.아래 코드를 참조해 주세요.
scrollToBottom= async ()=>{
document.getElementById('bottomID').scrollIntoView();
}
mweb/web에서 이 문제에 직면해 있습니다.이 페이지에서는 모든 솔루션이 양호하지만 안드로이드 크롬 브라우저를 사용하는 동안 모든 솔루션이 작동하지 않습니다.그래서 mweb과 web은 몇 가지 사소한 수정으로 해결했습니다.
import { createRef, useEffect } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'redux/store';
import Message from '../Message/Message';
import styles from './MessageList.module.scss';
const MessageList = () => {
const messagesEndRef: any = createRef();
const { messages } = useSelector((state: AppState) => state?.video);
const scrollToBottom = () => {
//this is not working in mWeb
// messagesEndRef.current.scrollIntoView({
// behavior: 'smooth',
// block: 'end',
// inline: 'nearest',
// });
const scroll =
messagesEndRef.current.scrollHeight -
messagesEndRef.current.clientHeight;
messagesEndRef.current.scrollTo(0, scroll);
};
useEffect(() => {
if (messages.length > 3) {
scrollToBottom();
}
}, [messages]);
return (
<section className={styles.footerTopSection} ref={messagesEndRef} >
{messages?.map((message: any) => (
<Message key={message.id} {...message} />
))}
</section>
);
};
export default MessageList;
이것은 Kent C가 가르쳐 준 useLayoutEffect의 훌륭한 사용 사례입니다.도드.
https://kentcdodds.com/blog/useeffect-vs-uselayouteffect
효과가 (DOM 노드 참조를 통해) DOM을 변환하고 DOM 변환에 의해 렌더링된 시간과 변환된 효과 사이에 DOM 노드의 모양이 변경되는 경우, useEffect를 사용하지 않을 수 있습니다.
제 경우 div 하단에 동적으로 요소를 생성하고 있었기 때문에 작은 타임아웃을 추가해야 했습니다.
const bottomRef = useRef<null | HTMLDivElement>(null);
useLayoutEffect(() => {
setTimeout(function () {
if (bottomRef.current) bottomRef.current.scrollTop = bottomRef.current.scrollHeight;
}, 10);
}, [transactionsAmount]);
const scrollingBottom = () => {
const e = ref;
e.current?.scrollIntoView({
behavior: "smooth",
block: "center",
inline: "start",
});
};
useEffect(() => {
scrollingBottom();
});
<span ref={ref}>{item.body.content}</span>
풀 버전(타입 스크립트):
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>
)
}
}
언급URL : https://stackoverflow.com/questions/37620694/how-to-scroll-to-bottom-in-react
'programing' 카테고리의 다른 글
React propTypes 컴포넌트 클래스? (0) | 2023.02.25 |
---|---|
각 메뉴 항목에 대한 추가 필드 추가 (0) | 2023.02.25 |
Redux Thunk와 Redux Saga의 차이점은 무엇입니까? (0) | 2023.02.25 |
reactj의 호버 상태에 액세스하려면 어떻게 해야 합니까? (0) | 2023.02.25 |
WordPress를 사용한 PHP if/else get_field() (0) | 2023.02.25 |