1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【React】最初っから下端にスクロールされている状態にする方法(アニメーションなし)

Posted at

はじめに

今回は、タイトルにある通り画面表示時、つまり任意のコンポーネントが表示された時にはすでに下端にスクロールされている状態にする方法について紹介していきたいと思います。

問題

LINEやDiscodeなどのチャット画面では、ページ表示時に一番下までスクロールされている状態が当たり前になっています。これをReactでやりたいというのが今回の目的です。

ここで試しに「React スクロール位置 下端」などで調べると、useRefuseEffectを使用して、最下部にスクロールさせる方法がよく紹介されています。
しかしこの方法だと、下までスクロールするアニメーションが表示されてしまいます。

LINEやDiscodeにそんなアニメーションはないですよね。
最下部にスクロールされた状態で画面表示をしたいのです。

以下にだいぶ無理やりにそれを実現した方法を紹介します。
もっといい方法を本当に知りたいので、知っている方はコメントで教えてください🙇🏻‍♂️

解決方法

一言で言えば、スクロール中はdiv自体を非表示にしてあたかもスクロールアニメーションをないように見せる、とういだけのゴリ押し戦法です。

今回はデータフェッチにSWRを使用しています。

const Chat: React.FC = () => {
    // この部分はSWRを使用したカスタムフックなので関係はなし。
    const {
        data,
        error,
        isLoading,
    } = useChat();

    const endDiv = useRef<HTMLDivElement>(null);

    const [isVisibility, setIsVisibility] = useState(false);

    useEffect(() => {
        // refがnullの時はスキップ
        if (endDiv.current) {
            endDiv.current.scrollIntoView();
            setIsVisibility(true);
        }
    }, [data]);

    return (
        <>
            <div
                style={{
                    visibility: isVisibility ? "visible" : "hidden",
                }}
            >
                // ここにチャットを展開
            </div>
            <div ref={endDiv} />
        </>
    );
};

各部の解説をしていきます。

const endDiv = useRef<HTMLDivElement>(null);

refはコンポーネントのDOMノードへの参照を持つオブジェクトです。
これを <div ref={endDiv} />のようにdivに指定することでこのdivのDOMを参照することができます。

const [isVisibility, setIsVisibility] = useState(false);

こちらはdivの表示非表示を動的に切り替えるために用意します。
デフォルト値はfalse、つまり非表示です。

useEffect(() => {
    // refがnullの時はスキップ
    if (endDiv.current) {
        endDiv.current.scrollIntoView();
        setIsVisibility(true);
    }
}, [data]);

useEffectでendDivのrefを持つdivまでスクロールさせます。
その後 setIsVisibility(true)でdivを表示状態に更新します。
また、これはapiからのフェッチを行うのが前提なのでdataを第二引数に指定し、dataがかわったタイミングで再レンダリングを行います。

今回はSWRを使用しているので、定期的に再検証させているとしても、レスポンスのdataが変わっている(新しいチャットがあった場合)時のみ最下部まで自動でスクロールしてくれます。

<div
    style={{
        visibility: isVisibility ? "visible" : "hidden",
    }}
>
    {/*ここにチャットを展開*/}
</ div>
<div ref={endDiv} />

visibility: isVisibility ? "visible" : "hidden",でisVisibilityによって表示非表示を切り替えます。

おわりに

かなり無理やりな実装ですが、とりあえずやりたかったことはできたので満足です。
もっといいやり方がみつかればまた更新したいと思います。
別なやり方等ありましたら是非コメントにお願いします🙏

では、最後までお読みいただきありがとうございました!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?