taiki-t's diary

きぎょうにっき, React Native, Rails そして雑多な記録: The world is waiting for you to give it the meaning.

Relay: containerのinitialVariablesに値を渡す

Introduction

非同期処理で何かごにょごにょした後、Relayにその値を使ってサーバーにリクエストを投げてほしかった。

やり方

Relay.createContainerを関数でラップする

雑な実装例:

componentDidMount() {
  this._asyncFunc()
}

async _asyncFunc() {
  try {
    let asyncVal = await someAsyncThings()
    this.setState({asyncVal})
  }
  catch (error) {
    console.log(error)
  }
}

render () {
  let component = null
  if (this.state.asyncVal) {
    component = (
      <Relay.RootContainer
        Component={createRelayComponent(this.state.asyncVal)}
        route={yourRoute}
        renderLoading={function() {
          return <div>Loading...</div>;
        }}
      />
    )
  } else {
    component = <div>Loading...</div>;
  }
  return component
}

function createRelayComponent(asyncVal) {
  return (
    Relay.createContainer(Component, { 
      initialVariables: {
        yourVar: asyncVal
      }

      fragments: { 
        ...
      }
    })
  )
}

参考リンク

Pass in React Component to Relay Variables and get a fragment from it. · Issue #775 · facebook/relay · GitHub

感想

他のやり方があれば教えほしい

React Nativeの画像キャッシュ

プロローグ

React Native使ってみた。Imageコンポーネント、毎回ネットワークから取得してるじゃん、これキャッシュしてくれないの?と思った。

調べた

[0.32] Image caching broken · Issue #9581 · facebook/react-native · GitHub

なんか壊れてんヨーという報告を発見。やっぱ壊れてんのかと思いつつ。 でもキャッシュしてもらえる人ともらえない人がいるみたい。日頃のおこない? ちなみに俺はキャッシュしてもらえてない。バージョンは0.38.0で。

なんでやねんと色々思っていると、画像サイズが大きいとダメだというコメントが目に入る。 画像サイズを小さくして試してみる。いけた。600KB -> 178kBぐらいに絞った。

どうやらReact Nativeは画像の取得にiOSに元からあるNSURLRequestという仕組み使っていて、そのNSURLRequestNSURLCacheさらにはNSURLSessionとやらの仕様にしたがってキャッシュを行うらしい。

そしてこのNSURLSessionは指定した上限の、5%までのファイルサイズしかキャッシュしないみたい。

で、React Nativeはどれほど指定しているのかなーと思ったら

  _decodedImageCache.totalCostLimit = 5 * 1024 * 1024; // 5MB

なるほど600KBはキャッシュされないですねと。てか上限小さすぎない?そしてそもそも

static const NSUInteger RCTMaxCachableDecodedImageSizeInBytes = 1048576; // 1MB

1MB以上のファイルはRN側でキャッシュしないように指定してるみたい。参照したのはここらへんhttps://github.com/facebook/react-native/blob/v0.38.0/Libraries/Image/RCTImageCache.m#L23

まぁただここらへんの挙動は変数名から推測した程度なので、自信はない。

TL;DR

画像サイズが大きいとダメみたい。250KB以下にした方が良さげ。 Imageコンポーネント、キャッシュしてくれる。シミュレーターでも動作が怪しいかもしれない。実機で動かしたらちゃんとキャッシュしてくれてた。

その他

[追記: 2017/3/30]

書き忘れていたけれど、画像をuriで指定して得るレスポンスのメタデータにcache-contolを含めていないとキャッシュしてくれない。 S3とかに上げるときは設定を確かめるのを忘れずに。

[追記: 2017/4/19]

Facebook内部ではオープンになってるコンポーネントとは別のImage, Cachingモジュールを使ってるみたい。 このIssueが閉じるまでは、Imageコンポーネントのキャッシュは安定しなさそう。自分の場合、3回ぐらいアプリ開くとキャッシュが消されるという挙動をしている。(0.43.3)

https://github.com/facebook/react-native/issues/9581#issuecomment-287834859

参考リンク

[0.32] Image caching broken · Issue #9581 · facebook/react-native · GitHub

Change RCTImageLoader's Cache System to default NSURLRequest's cache … · facebook/react-native@631785f · GitHub

https://github.com/facebook/react-native/blob/v0.38.0/Libraries/Image/RCTImageCache.m

URLSession:dataTask:willCacheResponse:completionHandler: - NSURLSessionDataDelegate | Apple Developer Documentation

ios - How to cache using NSURLSession and NSURLCache. Not working - Stack Overflow

浅草寺の思い出

数年前に浅草寺に行った。時期は忘れた。おみくじを引くところに年季の入ったお姉さん方が群がり、何やら盛り上がっていた。一人一人何が出たかを読み上げている。わたし小吉、わたしは吉。そして恋愛運がなんたらだとか。よくある光景だ。特に気にもとめず、そのままお堂の外に出ようとした。ところがそのとき、お姉さん方のひとりが放ったひとことに一瞬足を引き止められた。

「わたしはね、えーっと、『世界を統治する』って書いてある!何これー!」

ナニモンだよ、と。一人だけ恋愛だとか結婚だとかいう話題じゃなくて、何かとんでもないものを引き当てている。

その後が気になったけど、そのまま外に出ちゃったからあとのことは知らない。けれどきっと、世界は今その人のおかげで回っているんだと思う。ありがたや。まぁそんなことより、その人にとっては婚期の方が大事だったと思うけれど。

歓談はそして、立ち込める線香の向こうに消えていった。

Show an image on launch screen in React Native iOS app

My long attempts to show an image on launch screen (or splash screen) in iOS app with React Native have failed so far and here is a solution I finally found. The key is to make use of LaunchScreen.xib and not to use bunch of launch screen assets settings. (cf: xcode - iOS Launch screen in React Native - Stack Overflow )

1. Find LaunchScreen.xib

This blog post well describes how to find and edit LaunchScreen.xib so just watch it :How to Remove the “Powered by React Native” Message in iOS Apps | React Cafe. LaunchScreen.xib file is located under a file which name is the one you chosen for your app.*1

2. Provide image assets

Let’s provide assets. Find and select a file named Images.xcassets on XCode and show context menu with ctrl-click then select “New Image Set” as shown in an image below.

f:id:taiki-t:20170204191112j:plain

Drag'n'Drop images required in XCode. You may need to provide images which size are 1x, 2x and 3x. I named assets SplashIcon as shown in the image.

3. Set images in LaunchScreen.xib

This is the last step. Open LaunchScreen.xib then drag drop an Image View into a View.

f:id:taiki-t:20170204195119j:plain

Chose an image which added in the step 2.

f:id:taiki-t:20170204195817j:plain

Basically that’s all. You should be able to see the image you’ve set on launch screen. Make sure do Reset Content and Settings... on iOS simulator to reflect those changes if you are on the simulator.

Omake*2

Set constrains on the image in order to show it always in the center of the launch screens. Drag a connection with ctrl-clicking the image to the View. See this post to check required constrains: How to create ImageView center on storyboard using iOS? - Stack Overflow


*1:If you don’t want to use images (so as your logo) for your launch screen, that’s fine and just edit the screen. Actually Apple says “Don’t include logos or other branding elements unless they’re a static part of your app’s first screen.” and “Design a launch screen that’s nearly identical to the first screen of your app.” in their guide line for launch screen.

As far as I checked, some developers follow the guidelines and others don’t. Facebook, for example, follows the guidelines but Google mostly ignores it. Of course, Apple’s applications follow them. You might find it interesting to check out Apps on your device to see the difference of effects.

*2:https://en.wikipedia.org/wiki/Omake

React Native で文字を truncate

プロローグ

Railsって色々ヘルパーが用意されていて便利。ActionView::Helpers::TextHelper#truncateもその一つ。これは、文字列を切り詰めて末尾に...と付けてくれる。そういうヘルパーみたいなのがRNにもあったら便利だな?と思った。そしたら、あった。

numberOfLines と ellipsizeMode

ヘルパーメソッドとかじゃなくて、Textコンポーネントのprop指定でできる。numberOfLines で表示する行数を指定する。そして、ellipsizeModeであの...やつをどこに用いるかを指定できる。末尾に...をつけて省略したい場合、

<Text
  numberOfLines={1}
  ellipsizeMode={'tail'}
>
   longlongfoobarbazbarfoobarbazbar
</Text>

というような具合だ。これで ‘longlongfooba…’ のように表示されるようになる。...をつける箇所の指定の仕方は、公式ドキュメントに詳しい。ひとつ注意をあげるとすれば、ellipsizeModeを指定する場合はnumberOfLinesを指定する必要がある。

エピローグ

こうして無事truncateを自分で実装せずに済んだ。他にもonLayoutなどの指定できるpropがある。これらを適切に使うことで、不要であったり不適切な実装を避けることができる。ReactやReact Native, RelayといったFacebookOSSに触れていて素晴らしいと思うことの一つは、ドキュメントがきっちりと整備されていることだ。*1

*1:どこかで「FacebookOSSのポリシーとしてドキュメントが揃うまでリリースしない」という記述を見た気がしたけど、ソースを見つけられなかったので感想止まり。

S3のログから日付とアクセス元を漁るコマンドライン

プロローグ

S3のログ、見たいと思ったんだよね。アクセス時間と、アクセス元を。

やったこと

  1. ターミナル開く

  2. aws-cliをいれて設定などする
    brew aws-cli, aws configure
    詳しくは: http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html#config-cli

  3. ログを取ってくる
    あらかじめ保存先ディレクトリを用意して移動しておいて、
    aws s3 cp --region ap-northeast-1 s3://バケット名/ . --recursive
    参考: S3 から ファイルをAWSCLIでディレクトリごとダウンロード - Qiita
  4. ファイル結合
    find . -type f -exec cat {} + > 保存先のファイルパス
    参考: shell - cat files in current folder and all subfolders - Unix & Linux Stack Exchange
  5. 目的の文字列を抽出
    cat 保存したログのパス | cut -d ' ' -f 3,9,20 | grep 抽出したいアクセス元の名前 > 保存先のファイルパス

まぁ大方はこんな感じ。cut -d ' ' -fに指定する数字は必要に応じて調節すると良い。デリミタ(この場合空白 ‘ ')で区切った前から何番目という感じで指定できる。grepで特定のものに絞り込みたくない場合は、pecoに食わせてもいいかもね。

cat 保存したログのパス | cut -d ' ' -f 3,9,20 | peco

エピローグ

昨日は雪が降ってた

感情と雪解け

あれほど憎らしく思えた相手でも、その背景を知るとその気持ちがあっという間に変わることがある。それはさながら春の雪解けのように。実はその相手にものっぴきならない理由があって、たとえ自分がその発散の対象になったのは許しがたい事実だとしても、である。逆にそうであるからこそ、そのような現象になると言えるのかもしれないけれども。

しかしそうなるにも時間がかかる。いくつもの季節を巡り、やっと陽の光で溶けるところまで雪が降りてきてそれは初めて起こる。その時までは、本人にとっては長く辛い冬が続くけれども、その瞬間が来てしまえば、あいも変わらず外の世界で季節は回っていて、硬く鋼鉄のように思えた恨みつらみもそれは時と条件が揃えば解ける氷のようなものだったと知る。

氷雪の下を流れているちょろちょろという雪解け水の音を割り切れない気持ちでききながらも、確実に、穏やかに春の訪れを知る。そこからさらに山を下るためにはさらに時間も労力も必要だろう。けれど、そこまで降りてこれたのは事実だ。長い、孤独の冬山を耐え忍んで来たということは褒めてあげてもいいのかもしれない。

季節はさらに巡り続ける。緑が香れば、陽の光を讃える向日葵が咲き、そして熱帯夜が過ぎれば、葉が色づく。散りゆく葉を眺めては、やがて訪れる雪夜を想う。

人は厳しさの中にも、常々美しさを見出してしまう。そうしたくないと思っていても、たとえ白黒の世界に生きているとしても、ふとした瞬間に自分だけの美しさを見つける。しかし、その美しさはその時すぐに気づく類のものだとは限らない。未来のある時点で過去をふと振り返った時、あるいはそれがひょこと顔を出した時、あれは美しかったと思い出すものかもしれない。今朝の窓辺の霜のように。

生きるということは、その時のためにあるのかもしれない。

死んでしまえば、その瞬間は訪れないのだろうか。

何かの体験をどういう経験に変えるかは自分次第だ。人間には事実を真実に変える力がある。辛い体験だったとしても、ある一時それを美しい経験だったと思ったならば、それはその人にとっての真実となる。真実は誰にも奪えない。たとえ誰かが否定しても。

そうして人は生きていく。それは例えば狂気と呼べるかもしれない。あるいは –– 。

季節は今日もめぐりゆく。堪え難い冬を生き抜いた人が、今日もいる。

春の訪れを、ともに祝えたら良いと思う。