Skip to content

Instantly share code, notes, and snippets.

@adarapata
Last active January 9, 2019 02:12
Show Gist options
  • Save adarapata/1a9bc40221b015ec1052423e29937b5b to your computer and use it in GitHub Desktop.
Save adarapata/1a9bc40221b015ec1052423e29937b5b to your computer and use it in GitHub Desktop.
Rxあるある

Rxあるある


無限Subscribe

void Update() {
    this.UpdateAsObservable().Subscribe(_ => Foo());
}

  • 毎フレームObsrevableが生成されてしまう
  • 端末がアツくなる
  • 覚えたての頃にありがち

対処法

一回だけ呼びましょう

void Start() {
    this.UpdateAsObservable().Subscribe(_ => Foo());
}

Subscribe On Subscribe

void Start() {
    // ボタンを押したら通信する
    _button1.OnClickAsObservable
        .Subscribe(_ => {
            apiClient.Foo().Subscribe(response => {                
            })
        });

    // ボタン押したらUpdateのストリームが作られる
    _button2.OnClickAsObservable
        .Subscribe(_ => {
            this.UpdateAsObservable().Subscribe(_ => Foo());
        });
}
  • ストリームがガラッと変わるときにたまに見る
  • イベント駆動でObservableを作りたいときにたまにみる
  • ネストしてるのでけっこうつらい

対処法

  • 入れ子Subscribeは大体一本にできます
void Start() {
    // ボタンを押したら通信する
    _button1.OnClickAsObservable
        .ContinueWith(_ => apiClient.Foo())
        .Subscribe();

    // ボタン押したらUpdateのストリームが作られる
    this.UpdateAsObservable()
        .SkipUntil(_button2.OnClickAsObservable())        
        .Subscribe(_ => Foo());
}

switchストリーム

void Start() {
    var stream =_button.HogeAsObservable().Share();

    stream.where(hoge => hoge.State == State.Foo).Subscribe(hoge => hoge.Foo());
    stream.where(hoge => hoge.State == State.Bar).Subscribe(hoge => hoge.Bar());
    stream.where(hoge => hoge.State == State.Buz).Subscribe(hoge => hoge.Baz());
}
  • Hot変換などで、状態に応じた購読処理をストリームごと分岐している
  • 状態ごとにストリームが増えてしまう
  • 購読処理は短くなるが、そもそもそのコンテキストはストリームごと変えてしまってよいのか
  • DRYっぽくない(個人の感想)

対処法

  • Streamは分岐が得意ではないので素直にSubScribe内で分岐しましょう
void Start() {
    _button.HogeAsObservable()
           .Subscribe(hoge => {
               switch(hoge.State) {
                   case Foo:
                      hoge.Foo();
                      break;
                   case Bar:
                      hoge.Bar();
                      break;
                   case Baz:
                      hoge.Baz();
                      break;                      
               }
           });
}

ファットオペレータ


void Start() {
    var localBar;
    _button.HogeAsObservable()
           .Select(hoge => hoge.Fuga)
           .Where(fuga => fuga.Foo)
           .SelectMany(apiClient.ConnectBar)
           .Where(response => response.Success)
           .Do(response => localBar = response.Bar)
           .SelectMany(apiClient.ConnectBaz)
           .Where(response => response.Success)
           .Select(response => response.Baz)
           .Subscribe(baz =>  {
               view.Text = $"{localBar}:{baz}";
           });
}
  • 一本のストリームでやってることがでかい
  • Subscribeの内容が薄い
  • オペレータが便利故にすべて任せられるので、結果可読性がつらい
  • ラムダでアレコレするので名前を放棄しがち

対処法

適切な分割を心がけましょう

ReactiveProperty<Bar> bar = new ReactiveProperty<Bar>();
ReactiveProperty<Baz> baz = new ReactiveProperty<Baz>();

// �テキストを作るだけ
Observable.Zip(bar, baz, (bar, baz)=> $"{localBar}:{baz}").SubscribeToText(view);

_button.HogeAsObservable()
       .Select(hoge => hoge.Fuga)
       .Where(fuga => fuga.Foo)
       .SelectMany(ConncetBarObservable)
       .SelectMany(ConncetBazObservable)
       .Subscribe();

private IObservable<Bar> ConncetBarObservable(Foo foo) {
    return apiClient.ConnectBar(foo)
                    .Where(response => response.Success);
                    .Select(response => response.Bar);
}

private IObservable<Baz> ConncetBazObservable(Bar bar) {
    return apiClient.ConnectBaz(bar)
                    .Where(response => response.Success)
                    .Select(response => response.Baz);
}

まとめ

  • ストリームは分岐へた
  • ストリームは適切に分割を
  • 手続き的に書くのも大事

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment