最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to scroll only specific container in React? - Stack Overflow

programmeradmin2浏览0评论

I am trying to create a list in a React app, which the user can append items to. This list is in a div with a fixed height, so after some items, the user has to scroll. The behaviour I want to achieve is that when the user adds a new item to the list, the list scrolls to the end. What always happens, regardless of which solution I try to use, is that the whole page scrolls as well. I want the page to stay exactly where it is - the list itself should not move - and only the list div to scroll to its end.

This is my minimal working example, if you put this in a scrollable page that is.

const Test = () => {
    const [num, setNum] = useState([0, 1, 2]);
    const last = useRef(null);

    useEffect(() => {
        last.current.scrollIntoView({ behavior: "smooth" });
    }, [num]);

    return (
        <div
            style={{
                overflow: "auto",
                width: "100%",
                height: 300,
                background: "green",
                flexDirection: "column",
                justifyContent: "flex-start",
            }}>
            {num.map((numer) => (
                <div key={numer} style={{ height: 20, margin: 2, color: "blue" }}>
                    {numer}
                </div>
            ))}
            <button
                ref={last}
                onClick={() => {
                    setNum([...num, num.slice(-1)[0] + 1]);
                }}>
                Add number
            </button>
        </div>
    );
};

I am trying to create a list in a React app, which the user can append items to. This list is in a div with a fixed height, so after some items, the user has to scroll. The behaviour I want to achieve is that when the user adds a new item to the list, the list scrolls to the end. What always happens, regardless of which solution I try to use, is that the whole page scrolls as well. I want the page to stay exactly where it is - the list itself should not move - and only the list div to scroll to its end.

This is my minimal working example, if you put this in a scrollable page that is.

const Test = () => {
    const [num, setNum] = useState([0, 1, 2]);
    const last = useRef(null);

    useEffect(() => {
        last.current.scrollIntoView({ behavior: "smooth" });
    }, [num]);

    return (
        <div
            style={{
                overflow: "auto",
                width: "100%",
                height: 300,
                background: "green",
                flexDirection: "column",
                justifyContent: "flex-start",
            }}>
            {num.map((numer) => (
                <div key={numer} style={{ height: 20, margin: 2, color: "blue" }}>
                    {numer}
                </div>
            ))}
            <button
                ref={last}
                onClick={() => {
                    setNum([...num, num.slice(-1)[0] + 1]);
                }}>
                Add number
            </button>
        </div>
    );
};
Share asked Jul 5, 2022 at 15:16 Alex V.Alex V. 4565 silver badges15 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 4

I'm assuming you want the list to be scrollable, and the button SHOULD NOT move when items in the list increase. Therefore your button element should not be separated from parent div element that is scrollable using overflow: auto.

(Optional) For a better practice, your useRef should be referencing the parent div instead of the button element and you should name your variables properly.

After applying those changes, your code would look something like this:

import { useEffect, useState, useRef } from "react";

const Test = () => {
  const [numbers, setNumbers] = useState([0, 1, 2]);
  const listItems = useRef(null);

  useEffect(() => {
    const lastItem = listItems.current.lastElementChild;
    if (lastItem) {
      lastItem.scrollIntoView({ behavior: "smooth", block: "nearest" });
    }
  }, [numbers]);

  return (
    <div ref={listItems} style={{...}}>
      {numbers.map((number) => ...)}
      <button onClick={() => {...}}>Add number</button>
    </div>
  );
};

export default Test;

NOTE: The ... means that it's the same as your previous code.

BONUS TIP: If you want to create an array of numbers from 1...n, you can do this instead of manually typing all the numbers.

// Replace `n` with any numbers
const numbers = Array.from(Array(n)).map((_, i) => i + 1);
console.log(numbers);
发布评论

评论列表(0)

  1. 暂无评论