1
0

More than 5 years have passed since last update.

最後の4日間は、アプリケーションらしい UI のサンプルを紹介していきます。本日はメッセージアプリでよく見る chat board です。

なお、残念ながら本作は現状 iOS safari などで下部固定入力エリアの挙動不審が解決していません。メッセージが追加される毎にスクロール位置を移動し吹き出しを表示する処理はどこかで利用出来ると思います。
code: github / $ yarn 1222

1221-1.jpg 1222.jpg

メッセージの入力

Inputコンポーネントは、内部で入力テキストを保持しています。onCommitMessage の callback で、items を更新します。

components/index.tsx
export default (props: Props) => {
  const [items, updateItems] = useState<Item[]>([])
  return (
    <div className={props.className}>
      <List items={items} />
      <Input
        onCommitMessage={message => {
          const newItem: Item = {
            createdAt: new Date(),
            message
          }
          updateItems(_items => [...items, newItem])
        }}
      />
    </div>
  )
}

メッセージの挿入

props.items で受領するメッセージ配列が変化した時、吹き出しコンポーネントを生成、コンポーネント用配列に保持します。こうすることで、マウント済みコンポーネントの rerender 抑止をすることが出来ます。

components/list.tsx
const View = (props: Props) => {
  const nodeRef = useRef({} as HTMLDivElement)
  const [items, updateItems] = useState<JSX.Element[]>([])
  useEffect(() => {
    if (nodeRef.current === null) return
    const {
      height
    } = nodeRef.current.getBoundingClientRect()
    window.scrollTo(0, height)
  })
  useEffect(
    () => {
      if (props.items.length === 0) return
      updateItems(_items => {
        const newItem = props.items[props.items.length - 1]
        _items.push(
          <ItemComponent
            key={newItem.createdAt.getTime()}
            createdAtLabel={getTimeLabel(newItem.createdAt)}
            message={newItem.message}
          />
        )
        return _items
      })
    },
    [props.items]
  )
  return (
    <div className={props.className} ref={nodeRef}>
      {items}
    </div>
  )
}
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