hwclass.dev

moon indicating dark mode
sun indicating light mode

The Children of Redux — Part 2: Feeble, vdux and hyperapp

August 12, 2017

credit: Jessie Wilcox Smith credit: Jessie Wilcox Smith

In the first part of these articles, we have discussed about Plait, Dutier and dva. After a short investigation, I have found some others to use in applications especially if you need some quick solutions in prototyping process of your development.

Briefly and without giving any spoiler, Feeble is here for you to use as a different but simpler kind of immutable client state approach, vdux for provide local components states and managing applications like atoms and hyperapp for making development process easier by providing a functionality like Elm architecture as much as functional.

Feeble

The library contains a structure based on React, Redux and Redux sagas. Simplifies Redux implementation for start easily to prototype something based on a flux implementation or converting/refactoring a codebase into Feeble.

The another reason to use Feeble to get familiar more with some alternative implementations based on react and redux. Like in the first series of this article, you would easily migrate between to each other as well. It also works with React well.

Just before starting, we are adding some dependencies:

import React from 'react'
import ReactDOM from 'react-dom'
import feeble, { connect } from 'feeble'

Creating an instance from feeble function:

const app = feeble()

Generating a model for our counter example mentioned also in the repo’s readme file:

const counter = feeble.model({
namespace: 'count',
state: 0,
})

Invoking your actions to join with your interactions in user interface:

counter.action('increment')
counter.action('decrement')

And, of course, add a reducer to your model to have those changes happened:

counter.reducer(on => {
on(counter.increment, state => state + 1)
on(counter.decrement, state => state - 1)
})

At the end, binding your model with your application is enough:

app.model(counter)

Struct your view tree by exposing a new instance, for example called “App” :

const App = connect(({ count }) => ({
count
}))(function({ dispatch, count }) {
return (
<div>
<h2>{ count }</h2>
<button key="inc" onClick={() => { dispatch(counter.increment()) }}>+</button>
<button key="dec" onClick={() => { dispatch(counter.decrement()) }}>-</button>
</div>
)
})

We’re now mapping the whole data flow, bindings and actions with our view:

const tree = app.mount(<App />)

And render your application in DOM:

ReactDOM.render(tree, document.getElementById('app'))

If you need some async stuff (who knows not!), you may use effects which are based on sagas:

model.effect(function* {
yield* takeEvery(count.increment, function* ({ payload }) {
yield call(localStorage.setItem, 'count', payload)
})
})

One of the benefits of using Feeble is reusable reducers like the following by sending signals to your reducers just-in-place:

model.reducer(on => {
on(post.fetch.request, state => ({
...state,
loading: true,
}))
on(post.fetch.success, (state, payload) => ({
...state,
loading: true,
data: payload,
}))
})

There is also a hackernews application here built on this lovely structure.

vdux

A connection between redux and DOM as “virtualized”. The creator of the library believes that the state should be component-specific and the global state should be mutated by only applying a server-side rendering approach like the following:

function serverRender () {
const {state, html} = yield vdux(<App />)
this.body = `<html>
<head>
<script src='/vdux.js'></script>
<script src='/app.js'></script>
<script>
vdux(() => <App />, {
initialState: ${JSON.stringify(state),
prerendered: true
})
</script>
</head>
<body>
${html}
</body>
</html>`
}

A basic counter example to understand the approach better tells us that it uses the Redux terminology like reducers and actions to trigger in order to update the local state as well:

const TinyComponent = component({
render ({state, actions}) {
return <div onClick={actions.increment}>Value: {state.value}</div>
},
reducer: {
increment: state => ({
value: state.value + 1
})
}
}

You only need two fundamental functionality of the library to generate virtually-generated DOM and manipulate them: component and element:

import {component, element} from 'vdux'

Then, it is enough to return our tiny component as a return value of vdux function:

import vdux from 'vdux/dom'
vdux(() => <TinyComponent />)

hyperapp

This library provides another “plug & play” functionality for your evergreen applications which you hope to bring some innovative ideas into the wild! It is already as tiny as 1KB and minimalized as the creator mentioned in the readme file of the repo:

HyperApp was born out of the attempt to do more with less.

HyperApp totally inspired by the Elm Architecture and simplicity of doing things with functional programming paradigm as it is mentioned in the same readme file.

Using this library means you may see everything happening in front of your eyes like actions, the actual DOM of your component and state. That’s all what we need, right?

app({
state: {
count: 0
},
view: (state, actions) =>
<main>
<h1>{state.count}</h1>
<button onclick={actions.down}></button>
<button onclick={actions.up}></button>
</main>,
actions: {
down: state => ({ count: state.count - 1 }),
up: state => ({ count: state.count + 1 })
}
})

You can declare “dumb” components and use whereever you want throughout application structure:

const DumbComponent = ({ name, title, url }) =>
<h1>
<a href={url}>{name}, {title}</a>
</h1>

Every virtual node created contains three main parts: tag, data, children:

{
tag: "div",
data: {
id: "some"
},
children: [{
tag: "p",
data: null,
children: ["Some paragraph."]
}]
}

And it produces the following. You may also use the h function to reproduce the virtual DOM like the same:

<div id="some">
<p>Some paragraph.</p>
</div>

So, what about the component lifecycle methods? They are all provided by the library to handle the all steps of a component: load for the initial rendering moment of application, action for inspecting events just before being called, resolve for validating results of actions, update for tracking and doing things while changes happening and render for overriding the view function before it is called.

Here is the playground for hyperapp as well.

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

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


Baris Guler
Web worker