credit: Jessie Wilcox Smith

The Children of Redux — Part 1: Plait, Dutier and dva

Yes, I know that we sleep with Redux and wake up with it again! After the growing popularity of React library, focusing on the state management in the client-side becomes inevitably needed and resolves many issues. But also people (like me) are arguing about the “rituals” while we are using Redux as updating 3 or 5 files in different directories and so on. There is also some directory structure approaches for tidying every part of your state management up like ducks. But anyway, maybe we need another alternative to have a look and widen our perspective into new horizons.

To note, (and spoiler alert!) nearly every Flux/Redux alternative has nearly the same features like having almost declared actions, reducers to evaluate those actions into an actual state.

This article series are all about the possible successors of Redux and will probably be finishing with a proposal for better Flux/Redux alternative library approach for you.

Plait

A fast, minimal JavaScript framework for building isomorphic reactive web components! Sounds cool but what about coding conventions?

The following lines is for starting development with Plait:

import h from 'virtual-dom/h'
import Plait from 'plait'

The architecture and usage look really like the Elm API, so you have only 3 parts of your small component: init, view and update.

“view” is just a container for representing HTML markup collection of the component. “dispatch” method is just for sending notifications to “update” method to convert them as immutable states generated by Redux API.

const view = (state, dispatch) => {
return (
<div>
<button ev-click={dispatch({ type: 'DECREMENT' })}>-</button>
<span>{state.get('count')}</span>
<button ev-click={dispatch({ type: 'INCREMENT' })}>+</button>
</div>
)
}

update function listens for the changes during the lifecycle of the component and dispatches the actions and returns a new state. To note, update function is just a Redux reducer.

const update = (state, action) => {
switch (action.type) {
case 'DECREMENT':
return state.update('count', x => x - 1)

case 'INCREMENT':
return state.update('count', x => x + 1)
}
}

init is the initial state initializer. You may use it as returning an array with state and action for remote async calls.

const init = () => {
return {
counter: 0
}
}

After everything seems OK for you, you can connect everything into an instance.

const app = Plait.start({ init, update, view })

Then, choosing the correct DOM element to render will be the latest step for you:

Plait.render(document.getElementById('some-element'), app)

Plait uses virtual-dom library for immutability plus purity and in the readme file of the repo says that it is faster than any other libraries/frameworks like Elm, and etc.

Dutier

“Dutier is a small (1kb), async and powerfull state management solution for Javascript applications.” Alright, let’s have a look!

The methods we need to use for implementing the library into our project consist of 3 parts: reducer for evaluating the state and it is just literally a reducer like in Redux, createStore for connecting an actual store from that reducer with an actual component with subscription and the generated instance after the createStore gets the reducer as an argument. But at the end of the day, you only need “createStore” method to be imported. One more thing, you need action methods to use during manipulating the initial/updated state.

import { createStore } from 'dutier'

We are structuring the initial state:

const initialState = { label: 'Initial Label'}

Then, adding our reducer method:

const reducer = (state=initialState, { type, value }) => {
switch (type) {
case 'CHANGE_LABEL':
return { label: value }
default:
return state
}
}

Now, we are connecting the reducer with our current state:

const store = createStore(reducer)

This is the time to create our action method:

const changeLabel = (value) => {
return dispatch => {
dispatch({ type: 'CHANGE_LABEL', value })
}
}

Then, let’s add our React component to be an example for attaching state:

class SomeComponent extends Component {
constructor(props) {
super(props)
}
componentWillMount() {
this.unsubscribe = store.subscribe( { type, state } ) => {
console.log('Reducer new state value ', state, 'Store state: ', store.getState())
})
}
render() { //some content }
}

There is some tricky and a bit weird stuff here. The reason for putting the subscribe method into componentWillMount means the store change will be triggered just after the update props come.

Another cool feature is that returning only a promise when you call a dispatch event.

store.dispatch( changeLabel('Some New Label') )
.then( ({ type, state }) => {
console.log(type, state)
})

It is also possible to compose reducers into one reducer like combineReducers in Redux.

import { combine } from 'dutier'const labelReducer = (state={label: 'Initial Label'}, {type, value} {
switch (type) {
case 'CHANGE_LABEL':
return { label: value }
default:
return state
}
}
const titleReducer = (state={title: 'Initial Title'}, {type, value}) => {
switch (type) {
case 'UPDATE_TITLE':
return { title: value}
default:
return state
}
}
combine(labelReducer, titleReducer)

dva

“React and redux based, lightweight and elm-style framework. (Inspired by elm and choo)”. Cool, let see:

dva library looks like having a proper documentation for the developers who has just met with it and there says that there are 8 principles about the library: state (which is the state of the app), action (which is the first step for sending signals for updating the current state), dispatch function (which gets an action to update state as the second step), reducer (which gets state and action as arguments to handle/update state), effects (for async calls), subscriptions (which are for DOM events, etc.), router and router components.

If you are developing a simple application, you will need mostly the main api of dva with connect method and the Route and Router objects.

import dva, { connect } from 'dva';
import { Router, Route } from 'dva/router';
const component = dva()

First, let’s have a look at the view context:

const View = connect(({count}) => ({count}))((props) => {
return (
<div>
<h2>Some brilliant label</h2>
<span>{props.label}</span>
<button key="updateLabel" onClick={() => {props.dispatch({type: 'label/update'});}}>Update Label</button>
</div>
)
})

dva uses “model” keyword for your state:

component.model({
namespace: 'label',
state: '666',
reducers: {
update(label) {
return Math.floor(Math.random() * 10);
}
}
})

As we declare our router, we are using Router as a wrapper for whole Route(s):

component.router(({ history }) => {
return (
<Router history={history}>
<Route path="/" component={component} />
</Router>
)
})

At the end, it is enough to give the entry point of your application and that’s it:

component.start('#some-element-to-init-the-component')

Hope you like the article! Thanks for reading and see you in the next series.

Note: If you like this post, please share it on Twitter, or do something! :)

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store