14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Textコンポーネントをインライン要素っぽく扱う

Last updated at Posted at 2016-05-09

React Native v0.25.1でAndroidを中心に動作確認をしています。

TL;DR

React Nativeの<Text>コンポーネントは、ネストするとHTMLのインライン要素のように振る舞ってくれるので、テキストの装飾や、特定の文字だけにクリックイベントを持たせる用途に使えます。

React Nativeのテキストってインライン要素あったっけ

お仕事で本文中にハイパーリンクっぽいものを付けるようにUIデザインを書いてしまったのですが、よくよく考えてみたら、React NativeのTextコンポーネントはブロック要素っぽい振る舞いをしているところしか見たことがありませんでした。

例えば次のようなコードがあったとします。

index.android.js
<View style={styles.container}>
  <Text style={styles.welcome}>
    Welcome to React Native!
  </Text>
  <Text style={styles.instructions1}>
    To get started, edit index.android.js
  </Text>
  <Text style={styles.instructions2}>
    Shake or press menu button for dev menu
  </Text>
</View>

実際に描画されたViewをダンプしてみると、次のような構造になっていることが分かりました。

スクリーンショット_2016-05-09_23_21_49.png

ひとつのTextコンポーネントが、そのままひとつのTextViewになっているようです。

これがReactJSなら、<Text><a href="#">hogehoge</a>fugafuga</Text>のようにコンポーネントを組んで、テキストの一部だけを装飾したりクリックイベントを持たせたりできるのですが、残念ながらTextより小さい単位のテキスト用コンポーネントは存在しません。

Androidネイティブ的には、本文をSpannableStringで作ってしまえば装飾ができるのですが、Textコンポーネントではどうしたものやら。

HTMLのインライン要素的に一部のテキストだけを装飾する方法はないのでしょうか。

Textの振る舞いはひとつではなかった

結論からいうと、 Textの中にTextをネストすると、内側のTextがインライン要素のように振る舞う という挙動になります。

index.android.js
// ↓ViewではなくTextをコンテナとして使う
<Text style={styles.container}>
  <Text style={styles.welcome}>
    Welcome to React Native!
  </Text>
  <Text style={styles.instructions1}>
    To get started, edit index.android.js
  </Text>
  <Text style={styles.instructions2}>
    Shake or press menu button for dev menu
  </Text>
</Text>

スクリーンショット_2016-05-09_23_27_35.png

Viewの階層としては全部まとめてひとつのTextViewになっていますが、しっかりと装飾されています。Textコンポーネント単位でクリックイベントも持たせられることも確認できました。

こんな振る舞いをする輩はAndroidネイティブ界にも多くはいません。そう、SpannableStringです。

2016.5.9現在、v0.25のドキュメントではAndroid向けの挙動について言及されていないのですが、次バージョンであるv0.26のドキュメントでは、次のように言及されています。

Both iOS and Android allow you to display formatted text by annotating ranges of a string with specific formatting like bold or colored text (NSAttributedString on iOS, SpannableString on Android). In practice, this is very tedious. For React Native, we decided to use web paradigm for this where you can nest text to achieve the same effect.

ネイティブのテキストでも装飾はできるんだけど、面倒だからもっとWebっぽい手軽さでできるようにしようぜ!というマインドで作られた挙動のようです。うれしみ。

まとめ

内部実装まで追えたらよかったのですが、ネストの有無で使うコンポーネントを変えているあたりまでしか追えてないです。こういう風にrender対象のコンポーネントを差し替えていくの、Reactらしさだなあという感じはしました。

当初はreact-native-hypertextというプラグインを見つけて使おうとしていたのですが、実装をよく見たら単にTextコンポーネントのネストだったことで、この仕様を知った次第です。これくらいならプラグイン使わないほうが楽そう。

おまけ

ウォーターセル株式会社では、Reactで仕事がしたいWebエンジニアや、ネイティブでモバイルアプリ開発をしたいモバイルエンジニアを募集しています。地球人口100億人時代の食糧問題を解決する礎になるお仕事に興味がある方はご連絡ください。

14
9
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
14
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?