書き方が分かるまでに10時間以上かかったので、情報を共有します。
全体像
この流れで説明します。- 使ったもの
- ハマった点
- flat-listの書き方
- list-viewの書き方
- まとめ
使ったもの
- re-natalで開発しているアプリ
re-natalとはreact-nativeをclojure scriptで開発するためのフレームワークです。
下記のアプリを作っている時に、list-viewやflat-listの書き方が分からず、時間がかかりました。
re-natal-esp32control-app - 上記アプリの開発環境
$ re-natal --version 0.4.0 $ react-native -v react-native-cli: 2.0.1 react-native: 0.43.4
ハマった点
listのitemをレンダリングする処理をreagent/as-elementで囲って、reactのエレメントにする必要があります。そうでないと、下記のようなエラーが出て期待通りに表示されません。
StaticRenderer.render(): A valid React element (or null) must be returned. You may have returned undefined, an array or some other invalid object.
as-elementの具体的な書き方は、この後説明するflat-listやlist-viewを見ると分かると思います。
flat-listの書き方
下記のような記述で、上の画像のようなflat-listを描画できました。
(ns your-file-name-space
(:require [clojure.string :as str]
[reagent.core :as r]))
(def ReactNative (js/require "react-native"))
(def text (r/adapt-react-class (.-Text ReactNative)))
(def view (r/adapt-react-class (.-View ReactNative)))
(def flat-list (r/adapt-react-class (.-FlatList ReactNative)))
(defn item-flat-list []
(let [items [{:id "item-A"} {:id "item-B"}]]
(fn []
[view
[flat-list
{:data (clj->js items)
:key-extractor
(fn [item index]
(:id (js->clj item :keywordize-keys true)))
:render-item
(fn [item-info-js]
(let [item-info (js->clj item-info-js :keywordize-keys true)
{:keys [item index]} item-info]
(r/as-element [text (str index " " (:id item))])))}]])))
(defn your-page []
[view
[text "flat list sample"]
[item-flat-list]])
注意点
- ハマった点で説明したとおり、render-itemに渡す処理はreagentのas-elementでreactの要素にします
- flat-listはitemにkeyが含まれない場合、key-extractorでkeyの作成方法の指定します
- render-itemで渡されるデータはitemとindexのmapです
list-viewの書き方
下記のような記述で、上のようなlist-viewを描画できました。
(ns your-file-name-space
(:require [reagent.core :as r]))
(def ReactNative (js/require "react-native"))
(def text (r/adapt-react-class (.-Text ReactNative)))
(def view (r/adapt-react-class (.-View ReactNative)))
(def list-view-raw (.-ListView ReactNative))
(def list-view (r/adapt-react-class list-view-raw))
(def data-source (.-DataSource list-view-raw))
(defn item-list-view []
(let [items [{:id "item-A"} {:id "item-B"}]
data-source (new data-source
(clj->js {:rowHasChanged (fn [r1 r2] (not= r1 r2))}))]
(r/create-class
{:reagent-render
(fn []
[list-view
{:data-source (.cloneWithRows data-source (clj->js items))
:render-row (fn [item]
(let [item (js->clj item :keywordize-keys true)]
(r/as-element
[text (:id item)])))}])})))
(defn your-page []
[view
[text "list view sample"]
[item-list-view]])
注意点
- ハマった点で説明したとおり、render-rowに渡す処理はreagentのas-elemntでreactの要素にします
- list-viewに渡すデータはdata-sourceでの変換が必要です
- data-sourceのrowHasChangedの設定は、上記の記述で良いのか自信はありません(とりあえず動いてはいます)
まとめ
as-elementやclj->jsなどを駆使して、react-nativeのflat-listとlist-viewをre-natalで扱えました。同じような書き方でsection-viewも使えると思います。
ちなみに、scroll-view + for文でもリストを表示できるので、headerなどを利用しないシンプルなリストの場合は、その組み合わせで十分かも知れません。
共有する情報は以上です。
参考
FlatListListView
reagent.core/as-element




0 件のコメント :
コメントを投稿