Reswift: Integration of FRP Frameworks

Created on 10 Jan 2016  路  22Comments  路  Source: ReSwift/ReSwift

Unidirectional Data Flow and FRP play together nicely. We should consider how to provide an integration of FRP frameworks. Currently it's fairly easy to role your own, on top of Swift Flow, as shown in this example: https://gist.github.com/Ben-G/c33486169d68a6f3d12f

We should consider if integrations should become a core part of the framework or not; related discussion in ReduxKit.

Needs Discussion

Most helpful comment

I've rewritten part of ReSwift to accept any FRP library, needing only a small amount of boilerplate for conforming to protocols. I removed all of the delegate style subscription code and added a default FRP observable into ReSwift as ObservableType as well, which is only very basic and gives roughly the same amount of functionality as newState(_:) did.

https://github.com/Qata/ReSwift

Counter example with ReactiveSwift and ReactiveCocoa:
https://github.com/Qata/SwiftFoldExample

All 22 comments

I'm still exploring the framework but why Rxing the subscriber? not the store itself. Something like that may be:
https://gist.github.com/mosamer/824067f387f66b92c244

I'm exposing an Observable for interested entities (probably views) to subscribe to it. May be add some slicers (duals to reducers) to slice out the unneeded chunks of the app state. What do you think?

@mosamer When I first tested Rx integration I went with this approach as well. However, I was always planning on making MainStore a final class, once I came up with another implementation.

Relying on subclassing for adding functionality to MainStore is not ideal, since it will always only allow us to use one specific type of store. E.g. currently Swift Flow Recorder is also implemented as a MainStore subclass; which was a temporary solution that I would like to change moving forward.

What if you want a recording store that also supports exposing an Rx state? That wouldn't be possible if both functionalities are provided as subclasses of MainStore.

This is the main reason why my example uses an approach that can be used on any existing store, without the need for subclassing.

Still in search for the best approach!

Hi,

I'm trying out ReSwift and mixing it with RxSwift so it fits with my current UI implementation.

Working from @Ben-G's proposal I came up with this: https://gist.github.com/Odrakir/abf64b0712ec7348e30d960d22960830

In this case I pass a closure to the state method so I can map the main state to a substate. Also, as I made states Equatable, I can get updates only when that substate actually changes.

What do you think? Does it make sense?

@Odrakir did you ever take it further? Your solution seems to be nice, is it then that you can mix and match traditional vs rx store subscription? I'm also wondering what you do with the rxMiddleware..

Actually I'm taking it further. My goal is to use the redux style architecture with Rx for inputs and outputs. This is a proof of concept of something I'm working on, I'll probably release an article and some cleaner code soon: https://github.com/Odrakir/CachopoDemo

@Odrakir Nice, is there all ready something in there I could use.. I'm at the beginning of a new project. I did some projects with MVVM + Rx in the past and one small project with ReSwift, so thats why I'm interested in using both this time. Though admitting it is based on a gut feeling, I think Rx + ReSwift should be awesome.

I'm using in for two things:

  • Sending Async Actions to the store as an Observable<Action>
  • Subscribing to changes to the state Observable<AppState>

There are already some of those ideas in my repo, but as I said, a better version is on the works.

There are other approaches to mixing rx with redux, another one of them is this one: https://medium.com/@benlesh/redux-observable-ec0b00d2eb52#.a19u7dfh0

I've rewritten part of ReSwift to accept any FRP library, needing only a small amount of boilerplate for conforming to protocols. I removed all of the delegate style subscription code and added a default FRP observable into ReSwift as ObservableType as well, which is only very basic and gives roughly the same amount of functionality as newState(_:) did.

https://github.com/Qata/ReSwift

Counter example with ReactiveSwift and ReactiveCocoa:
https://github.com/Qata/SwiftFoldExample

That's great stuff, @Qata. I like the way yo merge every action into a single signal.

Finally, after much work around this in a real project, I think I'm opting for not touching ReSwift's code and just adding two extensions:

  • A RxMiddleware which gets actions in the form of an Observable
  • A wrapper around the Store to add that rxMiddleware automatically and also to convert subscription model into Observables.

My idea also implies using a Context I can pass to actions to do dependency injection using the Reader Monad. So async actions are not just Observable<Action> but rather ReaderT<Context,Action>. That part is a little more complex, I'll try to write a blog post about it soon. (for a start there's some info at the end of this article)

Though I really like your work @Qata, I tend to agree with @Odrakir. I think extending ReSwift to make it Rx'able has the advantage that any fixes or feature additions to the plain ReSwift will be more transparant and easier to maintain in the extension(s).

After some feedback from @agentk I've changed my implementation to add new types instead of altering existing ones.

@Ben-G @Odrakir @Qata, Question; For a current project I use a more simple flow. I use AsyncActionCreators for Observables (e.g. API calls) and in the subscription of these, use the callback param to dispatch actions with the obtained values. So, basically wrapping the side effects in an AsyncActionCreator. Anyone can tell me why this is maybe not the best approach?

So basically you are dispatching plain actions, but those dispatch calls occur for every event of an Observable. Right?

I think that should work.

My approach is a little different. I'm using a middleware that subscribes to those observables and transforms them to actions, that way I can directly dispatch observables.

The other thing that I'm adding is that they are not really observables, but readers (a monad that works somehow similar to curried functions) that get a context and return a observable.

https://gist.github.com/Odrakir/c95819f2162076f2fb45a366f704028b

I'll explain soon...

@Odrakir you are correct. Curious to read your explanation.

@Odrakir , looking forward to hearing more details on RxMiddleware.

Would you please also explain how your approach prescribes managing the lifetime of Reader monads. As well, as the API Client and Database objects?

Thanks in advance.

P.S. In the familiar case of "Model-View-whatever" the UIViewController holds the strong reference to the presenter. The presenter owns the model facade. The model facade interacts with the network and DB services and also holds strong references of them.

I'm really struggling to find out who is responsible of

  • invoking the services (Well, I guess, it's going to be your middleware)
  • managing their lifetime and disposing the resources correctly (that was my question, actually)

@Odrakir You may like what I did to Middleware in my fork of ReSwift. https://github.com/ReSwift/ReactiveReSwift/blob/master/ReactiveReSwift/CoreTypes/Middleware.swift
(It's a Reader that's generic over the State but takes Actions and returns Actions)

I think Netflix's redux-observable framework solves async action handling in a very elegant way.
They combine their reducers with some async action emitters they call "epics"..
https://github.com/redux-observable/redux-observable/blob/master/docs/basics/Epics.md

Hi,

I am trying to implement Netflix's redux-observable "Epics", mentioned by @Odrakir @erneestoc :
https://gist.github.com/r0nn/be7f29b91674bf54b5307c2ccf6efd83

Usage:

let incEpic: Epic = { actionSubject, getState in
    return actionSubject
        .filter{ $0 is CounterActionIncrease }
        .debounce(0.2, scheduler: MainScheduler.instance)
        .map{ _ in CounterActionDecrease() }
}

let epicMiddleware = EpicMiddleware(epic: incEpic)

let mainStore = Store<AppState>(
    reducer: AppReducer(),
    state: nil,
    middleware: [epicMiddleware.createMiddleware()]
)

Have tried in Counter example, looks not bad.

Hello, everyone.
I've got a question regarding an app architecture:

When you use ReSwift & RxSwift together do you use ReSwift for a global app state and RxSwift for a component specific state (i.e. input/output, intermediary state)?
How one uses RxSwift together with ReSwift, what layer of business logic does RxSwift handles?

(I am new to RxSwift, but have been working with Redux in React Natvie)

@r0nn: Indeed looking slick! But would you have to create an epic as middleware for every event handler that results in an action dispatch like that? 馃

@grundmanise: I use RxSwift mostly inside the UI layer, that is I subscribe to text field changes etc. In the end I reach the outer border of the UI layer in a service that subscribes to the UI events and dispatches actions to a store. You can populate the UI from ReSwift states with the convenience of libraries like "RxReSwift" and similar; then you can have Rx observables as store subscribers.

But even intermediary states go into the ReSwift state -- if they affect the program flow and are more than locally computed properties.

I like James K. Nelson: "The 5 Types Of React Application State" (August 29, 2016) http://jamesknelson.com/5-types-react-application-state/:

  1. Data
  2. Communication: pending requests; file operation queue
  3. Control State: view-specific state
  4. Session State: user information, settings
  5. Location State: navigation state; part of the URL in web apps; ReSwift-Router's current route's attached data

If anything that happens in my UI qualifies as communication state (outgoing: "user wants to delete the selected file") or control state (incoming: "show this image here"), it becomes part of the state managed by ReSwift.

That's just a heuristic I'm rolling with at the moment. It's not _The Truth鈩 (yet :)) and you might come up with something cooler.

Hi folks,

I'm an experienced iOS developer, and after half a year of JavaScript development using React and Redux, I became fond of the architecture pattern and found ReSwift. I have created a framework called ReRxSwift that decouples the view controllers from the application state and ReSwift actions in a manner similar to react-redux.

I would highly appreciate it if you could have a look and let me know what you think of it: https://github.com/svdo/ReRxSwift.

@svdo interesting, I would like to try it out. Did you ever checked: https://github.com/ReactorKit/ReactorKit ? Guess same goal, different approach.
Another (somehow different) interesting project worth checking out from the RxSwift initial creator is https://github.com/kzaher/RxFeedback (still in its very early stage).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ambientlight picture ambientlight  路  11Comments

CHOIMINSEOK picture CHOIMINSEOK  路  5Comments

nodediggity picture nodediggity  路  8Comments

dolanmiu picture dolanmiu  路  3Comments

coderMemberam picture coderMemberam  路  8Comments