書き方が分かるまでに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 件のコメント :
コメントを投稿