প্রতিক্রিয়া নীচে স্ক্রোল কিভাবে?


127

আমি একটি চ্যাট সিস্টেম তৈরি করতে চাই এবং উইন্ডোতে প্রবেশ করার সময় এবং নতুন বার্তাগুলি যখন আসবে তখন স্বয়ংক্রিয়ভাবে নীচে স্ক্রোল করুন you আপনি কীভাবে প্রতিক্রিয়াতে কোনও ধারকটির নীচে স্বয়ংক্রিয়ভাবে স্ক্রোল করবেন?

উত্তর:


221

তুষার যেমন উল্লেখ করেছেন, আপনি আপনার চ্যাটের নীচে একটি ডামি ডিভ রাখতে পারেন:

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

আমি এখানে স্ট্যান্ডার্ড এলিমেন্ট.স্ক্রোলআইন্টিভিউ পদ্ধতিটি ব্যবহার করছি ।


3
ডকুমেন্টেশন থেকে সতর্কতা: "FindDOMNode কার্যকরী উপাদানগুলিতে ব্যবহার করা যাবে না।"
টমাসজ মুলারসিজিক

1
this.messagesEnd.scrollIntoView()আমার জন্য ভাল কাজ করে। ব্যবহার করার দরকার নেই findDOMNode()
রজত সাক্সেনা

scrollToBottom(){this.scrollBottom.scrollIntoView({ behavior: 'smooth' })}এটি আরও নতুন সংস্করণে কাজ করতে ফাংশন পরিবর্তন করেছে
কুনোক

2
ঠিক আছে, আমি FindDOMNode সরিয়েছি। যদি এটি কারও পক্ষে কাজ না করে তবে আপনি উত্তরের সম্পাদনার ইতিহাস পরীক্ষা করতে পারেন।
metakermit

7
আমার একটি ত্রুটি আছে যে স্ক্রোলইন্টোভিউটি টাইপ এরির: অপরিজ্ঞাতকৃত সম্পত্তি 'স্ক্রোলআইন্টোভিউ' পড়তে পারে না। কি করো?
ফেরুজা

88

আমি কেবল নতুন 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/scroltobottomexample-f90lz আচরণটি পরীক্ষা করতে চান তবে একটি (খুব প্রাথমিক) কোডস্যান্ডবক্সও তৈরি করেছেন


2
কম্পোনেন্টডিডআপেট লাইফসাইলে অনেকবার কল করতে পারে। সুতরাং, আমাদের এটি পরীক্ষা করা উচিত। রেফারেন্স। ম্যাসেজেজ এবং বর্তমানের উপস্থিত রয়েছে কিনা স্ক্রোলটোবোটম ফাংশনে নেই। যদি এটি.মেসেজএন্ড.কন্টেনরটি বিদ্যমান না থাকে তবে ত্রুটি বার্তা প্রকারের ত্রুটি প্রদর্শন করবে: নালীর সম্পত্তি 'স্ক্রোলআইন্টোভিউ' পড়তে পারে না। সুতরাং, এটি যুক্ত করুন যদি শর্তটিও স্ক্রোল করুনবোটম = () => {যদি (this.messagesEnd.current) {this.messagesEnd.current.scrolIntoView ({আচরণ: 'মসৃণ'})}}
অর্পিত

কম্পোনেন্টডিডআপেট সর্বদা প্রথম রেন্ডারের পরে ঘটে ( reactjs.org/docs/react-component.html#the-comp घटक-lifecycle )। এই উদাহরণে কোনও ত্রুটি থাকা উচিত নয় এবং this.messagesEnd.currentসর্বদা উপস্থিত থাকে। তবুও এটি লক্ষ্য করা গুরুত্বপূর্ণ যে this.messagesEnd.currentপ্রথম রেন্ডারের আগে কল করার ফলে আপনি চিহ্নিত হওয়া ত্রুটি ঘটবে। Thnx।
দিয়েগো লারা

কি this.messagesEndscrollTo পদ্ধতিতে আপনার প্রথম উদাহরণে?
dcsan

@ ডি সি এস এটি একটি প্রতিক্রিয়া রেফ reactjs.org/docs/refs-and-the-dom.html#creating-refs
দিয়েগো লারা

1
দ্বিতীয় উদাহরণ কোড কাজ করে না। useEffectপদ্ধতি প্রয়োজন সঙ্গে স্থাপন করা হবে () => {scrollToBottom()}। যাইহোক ধন্যবাদ অনেক
গ্যাসপাড়

36

ব্যবহার করবেন না 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} />;
}

2
আপনি কেন DOMNode ব্যবহার করবেন না তা ব্যাখ্যা করতে পারেন?
একটি স্টিভি বোই

2
@ স্টেভিকিনস কারণ "এটি প্রতিক্রিয়াতে কিছু উন্নতি অবরুদ্ধ করে" এবং সম্ভবত github.com/yannickcr/eslint-plugin-react/issues/…
tgdn

2
আমেরিকান বানান হওয়া উচিত behavior(সম্পাদনা করতে পারে না কারণ "সম্পাদনাগুলি কমপক্ষে 6 টি অক্ষর হতে হবে", দীর্ঘশ্বাস)।
জো ফ্রিম্যান

1
জন্য সমর্থন scrollIntoViewসঙ্গে smoothমুহূর্তে খুব খারাপ।
আন্দ্রেইকুল

@ আন্দ্রেইকুল, আমি 'মসৃণ' ব্যবহারের সাথে একই রকম ফলাফল দেখতে পাচ্ছি বলে মনে হচ্ছে। এটি ধারাবাহিক নয়।
flimflam57

18

@ এলিটমেন্টকে ধন্যবাদ

আমাদের ব্যবহার এড়ানো উচিত 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();
}

রেফারেন্স:


আমি এই সমাধানটিকে সবচেয়ে উপযুক্ত বলে মনে করি, কারণ এটি ডিওমে নতুন (ডামি) উপাদান যুক্ত করে না, তবে বিদ্যমানটির সাথে আক্ষরিক অর্থে ডিল করে, ধন্যবাদ জে কে 2 কে
দেবপ্লেয়ার

7

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
  1. আপনার বার্তাগুলির ধারক উল্লেখ করুন।

    <div ref={(el) => { this.messagesContainer = el; }}> YOUR MESSAGES </div>
  2. আপনার বার্তাগুলির ধারকটি আবিষ্কার করুন এবং এর scrollTopবৈশিষ্ট্যটি সমান করুন scrollHeight:

    scrollToBottom = () => {
        const messagesContainer = ReactDOM.findDOMNode(this.messagesContainer);
        messagesContainer.scrollTop = messagesContainer.scrollHeight;
    };
  3. উপর পদ্ধতি উপরে আহ্বান 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>
        );
    }
}

6

প্রতিক্রিয়া-স্ক্রোলযোগ্য-ফিড স্বয়ংক্রিয়ভাবে সর্বশেষ উপাদানটিতে স্ক্রোল করে যদি ব্যবহারকারী ইতিমধ্যে স্ক্রোলযোগ্য বিভাগের নীচে থাকে। অন্যথায় এটি ব্যবহারকারীকে একই পজিশনে রেখে যাবে। আমি মনে করি এটি চ্যাট উপাদানগুলির জন্য বেশ দরকারী :)

আমি মনে করি যে এখানে অন্যান্য উত্তরগুলি স্ক্রোলবারটি যেখানেই ছিল না কেন প্রতিবারই স্ক্রোলকে বাধ্য করবে। অন্য সমস্যাটি scrollIntoViewহ'ল এটি যদি আপনার স্ক্রোলযোগ্য ডিভি না হয় তবে এটি পুরো পৃষ্ঠাটি স্ক্রোল করবে।

এটি এর মতো ব্যবহার করা যেতে পারে:

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

দাবি অস্বীকার: আমি প্যাকেজের মালিক


6

আমি বার্তাগুলির শেষে একটি খালি উপাদান তৈরি করেছি এবং সেই উপাদানটিতে স্ক্রোল করেছি। রেফার ট্র্যাক রাখার দরকার নেই।


আপনি এটি কীভাবে করেছেন
পেড্রো জেআর

@ মিমলা আপনি সাফারিতে যে সমস্যার মুখোমুখি হয়েছিলেন? এটি কি নির্ভরযোগ্যভাবে স্ক্রোল করে না?
তুষার আগরওয়াল

5

আপনি যদি প্রতিক্রিয়া হুক্স দিয়ে এটি করতে চান তবে এই পদ্ধতিটি অনুসরণ করা যেতে পারে। একটি ডামি ডিভের জন্য আড্ডার নীচে রাখা হয়েছে। এখানে ব্যবহারকারীর হুক ব্যবহৃত হয়।

হুকস এপিআই রেফারেন্স: https://reactjs.org/docs/hooks-references.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>
  );
}

5

সবচেয়ে সহজ এবং সর্বোত্তম উপায় হ'ল আমি সুপারিশ করব।

আমার ReactJS সংস্করণ: 16.12.0


এইচটিএমএল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"});
  }

এবং উপরের ফাংশন ভিতরে কল componentDidMount()এবংcomponentDidUpdate()

ডেভেলপার.মোজিলা.অর্গ.এর সম্পর্কে আরও তথ্যের Element.scrollIntoView()জন্য



4

আমি কাজের জন্য নীচের কোনও উত্তর পেতে পারি নি তবে সহজ জেএসগুলি আমার জন্য কৌশলটি করেছে:

  window.scrollTo({
  top: document.body.scrollHeight,
  left: 0,
  behavior: 'smooth'
});

3

কাজের উদাহরণ:

ভিউটিতে scrollIntoViewকোনও উপাদান দৃশ্যমান করতে আপনি ডোম পদ্ধতিটি ব্যবহার করতে পারেন ।

এই জন্য, উপাদানটি রেন্ডার করার সময় কেবল refঅ্যাট্রিবিউট ব্যবহার করে DOM উপাদানটির জন্য একটি রেফারেন্স আইডি দিন । তারপর পদ্ধতি ব্যবহার 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নির্দিষ্ট চ্যাট বার্তার অনন্য আইডি হিসাবে দেওয়া হয়েছে passedprops


আশ্চর্যজনক শেরিন ভাই এটি একটি কেকের মতো কাজ করছে T আপনাকে ধন্যবাদ
মোহাম্মদ সরফরাজ

@ মোহাম্মদ সরফরাজ আনন্দিত আমি সাহায্য করতে পারি :)
শেরিন জোস

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

1

আমি নিম্নলিখিত পদ্ধতিতে এটি করতে পছন্দ করি।

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

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

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

1

তার উত্তরের জন্য আপনাকে 'মেটেকারমিট' ধন্যবাদ জানাই, তবে আমি মনে করি আমরা এটিকে কিছুটা আরও উন্নত করতে পারি, নীচে স্ক্রোল করার জন্য আমাদের এটি ব্যবহার করা উচিত:

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


0

ব্যবহার 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>
                    )
        }
}

0

আপনি টাইপস্ক্রিপ্টে এটি কীভাবে সমাধান করবেন (কোনও লক্ষ্যযুক্ত উপাদানের রেফ ব্যবহার করে যেখানে আপনি স্ক্রোল করছেন):

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

প্রতিক্রিয়া এবং টাইপস্ক্রিপ্ট সহ রেফ ব্যবহার সম্পর্কে আরও তথ্যের জন্য আপনি একটি দুর্দান্ত নিবন্ধটি এখানে পেতে পারেন ।


-1

সম্পূর্ণ সংস্করণ (টাইপস্ক্রিপ্ট):

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>'. তাই ...
ডিসিএসান

ReactJS pls এর সংস্করণ? আমি 1.16.0 ব্যবহার করছি
টেকটার্টল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.