react 实现滚动条一直位于容易的底部

背景:js实现滚动条一直在底部靠的是元素的scrollTop和scrollHeight来实现的,可是在React中有些行不通。
原理:在容器的底部添加一个空的div,使该div一直处于浏览器视口内,这样就可以让容器的滚动条位于底部。
知识点:
useState: 通过在函数组件里调用它来给组件添加一些内部 state, useState 唯一的参数就是初始 state
useEffect:给函数组件增加了操作副作用的能力,它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。
useRef:返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。
Element.scrollIntoView() :让当前的元素滚动到浏览器窗口的可视区域内。
方案一:用hooks实现

import React, {useState, useEffect, useRef, PureComponent} from "react";
import ReactDOM from "react-dom";
import uuid from "uuid";

function Scroll() {
    const [messages, setMessages] = useState([]);

    const addMessages = () => {
        setMessages(m => [...m, uuid()]);
    };

    const messagesEndRef = useRef(null);

    const scrollToBottom = () => {
        console.log(messagesEndRef.current)
        messagesEndRef.current.scrollIntoView({ behavior: "smooth" });
    };

    useEffect(scrollToBottom, [messages]);

    return (
        <div className="App">
            <button className="addButton" onClick={addMessages}>
                Add message
            </button>
            <div style={{display:"flex", flexDirection:"column", height:"100px", overflow:"scroll", marginTop:"30px", border:"1px solid #000"}}>
                {messages.map(message => (
                    <span key={message}>{message}</span>
                ))}
                <div ref={messagesEndRef} />
            </div>
        </div>
    );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Scroll />, rootElement);

方案二:用类组件实现

import React, {useState, useEffect, useRef, PureComponent} from "react";
import uuid from "uuid";
class Scroll extends PureComponent {
    state= {
        messages: [],
        flag: false
    };

    componentDidUpdate(prevProps, prevState, snapshot) {
        const { message } = this.state;
        this.scrollToBottom();

    }

    scrollToBottom = () => {
        const messagesEndRef = document.getElementById("messagesEndRef");
        messagesEndRef.scrollIntoView({ behavior: "smooth" });
    };

    addMessages = () => {
        const { messages, flag } = this.state;
        // console.log(uuid());
        messages.push(uuid());
        this.setState({
            messages,
            flag:!flag
        })
    };

    render() {
        const { messages } = this.state;
        return (
            <div className="App">
                <button className="addButton" onClick={this.addMessages}>
                    Add message
                </button>
                <div style={{display:"flex", flexDirection:"column", height:"100px", overflow:"scroll", marginTop:"30px", border:"1px solid #000"}}>
                    {messages.map(message => (
                        <span key={message}>{message}</span>
                    ))}
                    <div id="messagesEndRef" />
                </div>
            </div>
        )
    }
}
export default Scroll

个人推荐第一种方案,第二种方案可行但是操作DOM性能一般。