OTOBANK Engineering Blog

オトバンクはコンテンツが大好きなエンジニアを募集しています!

FlatList の onViewableItemsChanged で起きたエラーを解決する

こんにちは、アプリ開発担当のエモトです。遊んでいたソシャゲが12月にサービス終了ということで、溜まった石やアイテムを使って、後先考えずに遊んでいます。アニメ作品のゲーム化なのでいつまで続くのか不安でしたが、2年弱も続いたので満足しております。なお、弊社本社近くのラーメン屋でガチャを回すと引きが良いです(個人調べ)。ガチャ好きな皆さまの入社をお待ちしております。

FlatList で今表示されている item の情報を取得するため、onViewableItemsChanged を利用したのですが、問題が起こり手間が取られてしまいました。今回はその問題と解決方法を共有したいと思います。なお、以降に提示するコード例は簡易的にしています。

問題

FlatList で表示されている item を取得しようと onViewableItemsChanged を利用しました。

const onViewableItemsChanged = ({viewableItems}) => { ... }
<FlatList onViewableItemsChanged={onViewableItemsChanged} />

すると、エラーが出てきました。しかも、このエラーは常にではなく、ホットリロード時に起こるなど、特殊なエラーでした。

Changing onViewableItemsChanged on the fly is not supported

調べると、

At least one of the viewAreaCoveragePercentThreshold or itemVisiblePercentThreshold is required.

とのことなので、viewabilityConfig に値を設定しました。

const onViewableItemsChanged = ({viewableItems}) => { ... }
const viewabilityConfig = {
  itemVisiblePercentThreshold: 50,
}
<FlatList
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={viewabilityConfig}
/>

しかしながら、エラーは治りませんでした。

解決

viewabilityConfig の公式ドキュメントを読むと、気になる一文がありました。

This needs to be done in the constructor to avoid following error

リンクされていた issue を読むと、render のタイミングで生成して渡すとダメな仕様でした。解決方法は分かったものの、私は関数コンポーネントで作成していたので、クラスコンポーネントの constructor に対応するものは何?と悩むことに。いろいろ調べ試すと今回は useRef() で良いと分かりました。

const onViewableItemsChanged = useRef(({viewableItems}) => { ... })
const viewabilityConfig = useRef({
  itemVisiblePercentThreshold: 50,
})
<FlatList
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={viewabilityConfig}
/>

やっと無事に動きました。私の中に useRef() に関数を入れる発想はなかったので、時間がかかってしまいました。

まとめ

FlatList の仕様と、クラスコンポーネントのメソッドを関数コンポーネントで書くにはどうすればいいんだという2つの問題を踏み抜いて、久々に沼ってしまいました。改めて、こういうシーンでは、

  • ドキュメントを漁る
  • 関数コンポーネントとクラスコンポーネントの比較

に立ち返るのが良いですね。この FlatList の仕様は他の方でもハマりそうな問題だと思うので、少しでも参考になれば幸いです。