前回は、画面に表示されている日付を、 SNS のように〇〇時間前にしました。

今回は、最新メッセージが表示されるよう、ローディング後、一番下の画面まで移動します。

最新のメッセージが一番下にくるよう設定しています。

image2

メッセージが増えると、

image3

下の文字が見えなくなってしまいます。

リロードすると、

image4

一番古いメッセージが一番上に来てしまいます。

こちらを、最新のメッセージが一番下に表示されるようにします。

まずは、画面の要素を参照するために、Home.tsx でuseRefを使用します。

react からuseRefをインポートしましょう。

import React, { useRef } from "react"

useRef を設定しましょう。

const bottomRef = useRef<HTMLDivElement>(null)

画面遷移させるために、react からuseLayoutEffectをインポートします。

import React, { useLayoutEffect, useRef } from "react"

useLayoutEffect内でscrollIntoViewを使い、スクロールするよう設定します。

useLayoutEffect(() => {
  bottomRef?.current?.scrollIntoView()
})

メッセージ一覧の一番下に、<div ref={bottomRef}></div>を挿入します。

return (
  <Box sx={{ flexGrow: 1, m: 2 }}>
    {messages ? (
      messages.map((message: Message) => (
        <Box
          key={message.id}
          sx={{
            display: "flex",
            flexDirection:
              profile && profile.uid === message.user.uid
                ? "row"
                : "row-reverse",
            my: 2,
            gap: 2,
          }}
        >
          <Box>
            <Avatar src={message.user.image ? message.user.image : ""} alt="" />
          </Box>
          <Box>
            <Typography sx={{ p: 1, background: "#dddddd", borderRadius: 1 }}>
              {message.text}
            </Typography>
            <Typography sx={{ fontSize: 12 }}>
              {time(message.createdAt)}
            </Typography>
          </Box>
        </Box>
      ))
    ) : (
      <p>メッセージが存在しません</p>
    )}
    <div ref={bottomRef}></div>
    <MessageInput />
  </Box>
)

では、動作確認しましょう。

画面をリロードすると、

image5

最新メッセージが一番下に来ています。

このままでは、メッセージ入力画面と被っており、またヘッダーが見えなくなっているので、修正しましょう。

Home.tsx のreturn下のBoxpt: 6, pb: 4を指定します。

<Box sx={{ flexGrow: 1, m: 2, pt: 6, pb: 4 }}>

Header.tsx のreturn下のBoxposition: “fixed”などを設定し、ヘッダーを固定します。

<Box
  sx={{
    flexGrow: 1,
    position: "fixed",
    top: 0,
    width: "100%",
    zIndex: 9999,
  }}
>

では、画面リロードし、確認しましょう。

image6

最新メッセージが一番下に来て、ヘッダーも上部にあります。

試しにメッセージを送ってみると、

最新メッセージが表示されました。

image7

今現在、入力欄にメッセージが残っているので、送信後はメッセージを消します。

MessageInput.tsx で送信後にmessageを空にします。

try {
  const docRef = collection(firestore, "messages")

  await addDoc(docRef, {
    text: message,
    createdAt: Timestamp.fromDate(new Date()),
    user: {
      name: profile?.name,
      image: profile?.image,
      uid: profile?.uid,
    },
  })
  setMessage("")
} catch (err) {
  console.log(err)
  setError(true)
}

TextFieldvalueを設定します。

<TextField
  size="small"
  sx={{ flex: 1 }}
  value={message}
  onChange={e => setMessage(e.target.value)}
/>

では、メッセージを送信してみましょう。

image8

送信ボタンをクリックすると、

image9

入力欄のメッセージが消えました。

ブログ一覧