Hyperapp: Calling actions from within an action

Created on 6 Jan 2018  路  9Comments  路  Source: jorgebucaran/hyperapp

I am getting some results I'm finding difficult to comprehend when I am calling actions from within an action, eg. the action setS1rS2 (on button S1rS2) compared to action setS1S2 in jsfiddle https://jsfiddle.net/WarwickGrigg/eo537smc/

Using latest hyperapp v 1.0.1. Excerpt below:

const actions = {
  setS1: dt => (_, actions) => { return {s1: dt} }, // changes state
  setS2: dt => (_, actions) => { return {s2: dt} }, // changes state
  setS1S2: dt => (_, actions) => {
    actions.setS1(dt); // changes state
    actions.setS2(dt); // changes state
  },
  setS1rS2:dt => (_, actions)  => {
    actions.setS1(dt); // no effect (!)
    return {s2: dt};   // changes state for s2
  },

Results are different but even more confusing (for me) if I remove the '=> (_, actions)' action function wrapper. Is there something special about calling actions from within an action?

Bug

Most helpful comment

Okay, I found the fix changing line 107 to:

if (data && data !== (slice = get(path, state)) && !data.then) {
  repaint((state = set(path, copy(slice, data), state, {})))
}

The interesting part is:

slice = get(path, state)

that basically computes the slice afresh.

All 9 comments

@warwickgrigg Nice find! I introduced this bug here.

We need to compute the substate/slice again before merging with the state.

I'll fix it over the weekend. 馃憤

Okay, I found the fix changing line 107 to:

if (data && data !== (slice = get(path, state)) && !data.then) {
  repaint((state = set(path, copy(slice, data), state, {})))
}

The interesting part is:

slice = get(path, state)

that basically computes the slice afresh.

Thanks, Jorge. And thank you for hyperapp - very promising and elegant. I've created a jsfiddle fork here https://jsfiddle.net/WarwickGrigg/rqqzqb9n/ with the action functions omitting the => (_, actions) wrapper, annotating the results:

const actions = {
  setS1: dt => { return {s1: dt} }, // changes state
  setS2: dt => { return {s2: dt} }, // changes state
  setS1S2: dt => {
    actions.setS1(dt); // no effect
    actions.setS2(dt); // no effect
  },
  setS1rS2:dt => {
    actions.setS1(dt); // no effect (!)
    return {s2: dt};   // changes state for s2
  },
  setS1cS2:dt => {
    s1obj = actions.setS1(dt); // assume no effect (?), but returns obj
    return Object.assign([], s1obj, {s2: dt}); // changes state`

@warwickgrigg Done! 馃挭

@warwickgrigg Published as 1.0.2! 馃帀

Turns out the fractals example was a victim of this bug, but it now works again.

But isn鈥檛 it good to never, ever rely on multiple synchronous state updates and merge them before returning something instead?

@infinnie What?

how i can use it now?

@maxbaluev use what?

Calling actions in actions, in the latest release 1.2.6 (or is it 1.2.9?) works as described in the docs.

myMultiAction: data => (state, actions) => {
  actions.action1(data.foo)
  actions.action2(data.bar)
}

Calling actions in actions won't work in V2. Instead you will have to compose the actions, like @infinnie suggested earlier in this thread.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dmitrykurmanov picture dmitrykurmanov  路  3Comments

joshuahiggins picture joshuahiggins  路  4Comments

zhaotoday picture zhaotoday  路  3Comments

guy-kdm picture guy-kdm  路  4Comments

dmitrykurmanov picture dmitrykurmanov  路  4Comments