Why do I write Sinux, a flux inspired library for React Native

Back in 2010, my resume title was Adobe Flex developer. At this time, developers on Adobe technologies were rock stars.

Jean-Baptiste PIN
6 min readDec 28, 2015

Big companies, creative studio’s and web agencies were looking for such profiles. Adobe were doing big conferences all over the world that were the equivalent of Web conferences you can find now.

If you had been a web developer or a RIA developer during this time, for sure you would have been to one on these conferences and inevitibly worn a t-shit with the Adobe logo on it (no kidding).

With Flex and AIR you could have built an app for a wide range of devices. Web, Native app, TV, phone but sadly, not watches… yet..

Adobe Flash Platform

MVC framework were starting to emerge from the community, so far I can remember a few of them were trending but I can remember one in particular.

The last application (MySnapper) I developed in AS3 was a Flex/AIR cross platform native application that uses Robotlegs.

Then came HTML5 and CSS3 with video and sound support, iOS with their no flash policy and eventually Adobe sacrificed Flex and gave it to Apache.

Abode Flash Platform

React Native and Redux

I’m still a developer and I follow the move, flipping from AS3/Flex/Air to HTML5/CSS3/Js. I used jQuery for years, then Angular, and eventually tried Backbone, EmberJs etc.. I did web development as mobile hybrid application using Cordova.

A few months ago, I started a new project and I discovered React Native. This was just what I was looking for to jump on React. I watched conferences on the subject, read tons of articles on React, Web components, es6, flux architecture.

I was ready to start, I got my stack, my plan and all the confidence you need when deciding to go for a technology that is quiet new.

I managed to define three main behavioural qualities:

  • Asynchronous call
  • Side Effect
  • Optimistic UI

I was ready to use Redux, I found it clear, easy to develop and test, with a large support base and an active development. But React 0.16 was shipped with Babel6, and I wanted to use ECMAScript 2015, as they will probably not be rolling back on Facebook. React-Redux was not ready to support React Native 0.16 (BTW, Facebook is working on an issue that should solve this so it will soon become an old story).

Another thing came to mind. I was a bit upset having to create a long list of constants for defining which actions I need to use in my application. I knew it was an issue in AS3 but I was not crossing this bridge at present.

Asynchronous call

The app will have to use several API and asynchronous calls, also all the business logics will have to stand in one layer. In action or reducer, or wherever it will make sense. Action doesn’t make sense to me. They are just something happening in the system. Some action creators return objects, others return functions. It was not consistent.

I need to have a way to watch for an asynchronous action so that I can have indicators regarding the state of the call rather than having to maintain a state in my store.

Promise/Generator/Yield

ES6 comes with Promise, Function generator with yielding. There is ES7 coming with async/await pattern. It was obvious to me that there was a path to follow in order to undertake an asynchronous call.

For most of the time I was looking for my stack, I was looking for a way to put my business logics in a layer that would be clear for everyone in my team where to find them.

I was not happy with putting them in actions, nor in Store as suggested by the Facebook documentation. I needed something granular. I also wanted to use new features like Promises and Generator function.

I found a project called redux-saga that allowed me to handle side effect using function generator.

It was clearly known that I wanted to use Generator Function or a similar pattern.

I finally found tj/co. It’s a library write by TJ Holowaychuk :

“Generator based control flow goodness for nodejs and the browser, using promises, letting you write non-blocking code in a nice-ish way.

With co I can yield almost anything :

  • function
  • promises
  • thunks (functions with callback)
  • array or objects for parallel execution
  • generators and generator functions

“Nested ‘yieldable’ objects are supported, meaning you can nest promises within objects within arrays, and so on!”

Signal

Here is a rough comparaison of Signals over Events

Events:

  • Rely on String
  • Single dispatcher
  • All listeners will receive events the same if they do not process it
  • Type/Class less
  • Data is passed by using payload

Signals:

  • Rely on Object
  • Self dispatching
  • Only listeners attached to the signal will be called
  • Listeners (Command) have a signature

Events over Signals in Flux mean having a bench load of listeners to be called every time an action is dispatched. I also need to know the name of the event I want to process or fire. To be sure I will not misspell its name, I can use constants, so by having a bench load of constants to maintain, I am not sure that I will not duplicate one. Afterall, working alone on a project is challenging but in a bigger team it becomes a nightmare.

With signal, I got an object that dispatched itself and called all the attached listeners. All listeners have a signature and so I can handle any error and fail gently and effectively. I can also pass them through the app, between stores etc.

I’m not relying on String anymore, and more importantly, I am not misspelling their names or duplicate them. Also, having them to rely on object means I don’t have to worry about removing listener in a single point (dispatcher) and thus avoiding memory leaks.

Sinux

Back to my stack, I start thinking on how I can use Signal for triggering business logic element that reside in one layer and use Promise or Generator function with the co library.

I remember the time I was developing in AS3 using Robotlegs. We use signals that were injected into a view mediator/presentation model, and views were plugged to the mediator or presentation model and injected into it. Signal’s dispatch method was called and a command was triggered. In that way view were decoupled from the data. I find it very intelligent and easy to maintain.

I want something similar and simple to test. I start creating a class for Store with basic function (updateState, getState) and Signal class simple as well (dispatch, addListener, removeListener). Now I have to pair this element and have a business layer to handle actions. I create a Command class with only one method ; execute.

Finally, I am able to create stores, signals and commands. Signal are simple objects that hold listeners (commands) that update the stores when they finish processing. Here is how I came to attach Signal to Store. When creating a Store, store will create and hold Signals and in doing so, will be responsible for them.

var userStore = new Store({}, ‘create’, ‘login’, ‘logout’, ‘update’, …)new Command(userStore.create, function* (username, email, password){
try{
let result = yield api.createUser(username, email, password)
return result.user
}catch(e){

}
}())
new Command(userStore.create, function* (username, email, password){
analytic.event(‘user created’, {username, email})
}())
new Command(userStore.update, function(userId, user) {
return new Promise((resolve, reject) => {
api.updateUser(userId, user, (result, err) => {
if(err){
return reject(err)
}
resolve(result.user)
}
)
)
})

In the same way, commands can be executed without depending on store.


let action = new Signal('action')
new Command(action, (...args){
...
}

Each command can be defined in a separate file and loaded on the application entry point.

MySinuxApp
| — store
| — — user.js
| — command
| — — user
| — — — login.js
| — — — update.js
| — api.js
| — index.js

You can find a link to an example react-native todo app in the repos of the project jbpin/sinux

Each Signals is dispatch using the store instance.

userStore.udpate(1, {username: jbpin, ..})

You can pass signals in command as an argument and because dispatch returned a promise you can also yield for them (waitFor behavior).

When dispatching a signal from a container, you can update the state of sub components and listen for the promise ending to restore the state. By using this method, you can manage ActivityIndicator and other systems.

Conclusion

I’m now using Sinux in my project, it’s a young project and I don’t have much feedback to give. There is still work to be done on reproducing some of redux middleware and tools. Please feel free to download it and try it. I’m looking for feedback on your experiments. I’m also looking for contributors to improve and maintain the project. Feel free to get in touch Jean-Baptiste PIN (@jbpin) on twitter or in the gitter of the project.

--

--

Jean-Baptiste PIN

Business and Innovation designer. I help early stage company to succeed. #product #user #innovation #+minded