जवाबों:
जैसा कि तुषार ने उल्लेख किया है, आप अपनी चैट के निचले भाग में एक डमी 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बनाए गए रेफरी में संपत्ति को ध्यान में रखें :
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हुक के उपयोग को जोड़ने के उत्तर को अपडेट कर रहा हूं , असली चीज़ जो जादू कर रही है (रिएक्ट रिफ और scrollIntoViewडोम विधि) वही रहती है:
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स्क्रोल्टो विधि में आपके पहले उदाहरण में क्या है ?
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साथ समर्थन 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();
}
}
}
यदि उपयोगकर्ता पहले से ही स्क्रॉल करने योग्य अनुभाग के निचले भाग में था, तो प्रतिक्रिया-स्क्रॉल करने योग्य-फ़ीड स्वचालित रूप से नवीनतम तत्व तक पहुंच जाता है। अन्यथा, यह उपयोगकर्ता को उसी स्थिति में छोड़ देगा। मुझे लगता है कि यह चैट घटकों के लिए बहुत उपयोगी है :)
मुझे लगता है कि यहां अन्य उत्तर हर बार स्क्रॉल को बाध्य करेंगे, चाहे जहां भी स्क्रॉलबार हो। इसके साथ दूसरा मुद्दा 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>
);
}
}
मैंने संदेशों के अंत में एक खाली तत्व बनाया, और उस तत्व को स्क्रॉल किया। रेफरी पर नज़र रखने की कोई आवश्यकता नहीं है।
यदि आप रिएक्ट हुक के साथ ऐसा करना चाहते हैं, तो इस विधि का पालन किया जा सकता है। एक डमी div के लिए चैट के नीचे रखा गया है। useRef Hook का उपयोग यहाँ किया जाता है।
हुक एपीआई संदर्भ: 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.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
काम करने का उदाहरण:
आप scrollIntoViewदृश्य में एक घटक को दृश्यमान बनाने के लिए DOM विधि का उपयोग कर सकते हैं ।
इसके लिए, घटक का प्रतिपादन करते समय, 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गए विशेष चैट संदेश की विशिष्ट आईडी है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>
);
}
}
मैं इसे निम्नलिखित तरीके से करना पसंद करता हूं।
componentDidUpdate(prevProps, prevState){
this.scrollToBottom();
}
scrollToBottom() {
const {thing} = this.refs;
thing.scrollTop = thing.scrollHeight - thing.clientHeight;
}
render(){
return(
<div ref={`thing`}>
<ManyThings things={}>
</div>
)
}
उसके अच्छे उत्तर के लिए आपको 'मेटाकर्मीट' धन्यवाद, लेकिन मुझे लगता है कि हम इसे थोड़ा बेहतर बना सकते हैं, नीचे स्क्रॉल करने के लिए, हमें इसका उपयोग करना चाहिए:
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>
)
}
}
यह है कि आप इसे टाइपस्क्रिप्ट में कैसे हल करेंगे (लक्षित तत्व के रेफरी का उपयोग करके जहां आप स्क्रॉल करते हैं):
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 * 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>'. इसी तरह ...