okwolf/hyperapp-fx

nested actions bug report

willin opened this issue · 12 comments

this is ok:

// actions
const actions = {
  // always here
  set: ({ key, val }) => ({ [key]: val }),
  ticket: () => [
    action('set', { key: 'loading', val: true }) // default value false
  ]
}
// view
<h1 onclick={action('ticket')}>{String(state.loading)}</h1>

Uncaught Error: couldn't find action: set

// actions
const actions = {
{
  set: ({ key, val }) => ({ [key]: val }),
  ticket: {
    list: () => [
      action('set', { key: 'loading', val: true })
    ]
  }
}
// view
<h1 onclick={action('ticket.list')}>{String(loading)}</h1>

Thanks for the 🐜 report @willin.

I will take a look at this later 🕵️

ticket: {
    set: ({ key, val }) => ({ [key]: val }),
    list: () => [
      action('set', { key: 'loading', val: true })
    ]
  },

this action can be triggered, but in this way i had to define a lot of setters
and when get it a PREFIX is needed

On second look, this is working as designed. Slices can only see state and actions in their own namespace and below.

like this design, each module has its own actions.

and some are common (or namespace called global)

how to call those actions ( such as in action('ticket.list') to call action('set') global set)

This is how slices work generally in Hyperapp. This library doesn't try and break out of your current namespace when calling actions. If you want to update global and slice state then call actions at the root of your tree and have those call down the hierarchy to the slices of interest.

For more info please read the section in my blog article on this subject.

thx. here's another problem:

import { h } from 'hyperapp';
import { action } from '@hyperapp/fx';

const getTickets = () => {
  action('ticket.list'); // not run
  console.log('123'); //called and printed
};

export default ({ ticket: { loading } }) => () => (<main>
    <h1 key="tickets">
      <span oncreate={getTickets}>{String(loading)}</span>
    </h1>
  </main>);

but in this way, it can run:

import { h } from 'hyperapp';
import { action } from '@hyperapp/fx';

export default ({ ticket: { loading } }) => () => (<main>
    <h1 key="tickets">
      <span oncreate={action('ticket.list')} >{String(loading)}</span>
    </h1>
  </main>);

@willin calling fx creator functions like action don't actually cause any action to fire, but instead should be returned to Hyperapp from actions or attached to event handlers in your view. If you immediately know what fx to run in your event handler then you can assign that directly like in your second example.

To do logic like you have in your getTickets function, you should look at the event effect and do the work in the action you decide to call from there. By the way, you can write custom fx to do pretty much anything you want if you want to make this logic reusable.

is there an example of how does custom fx works?

@okwolf

a simple example, i have two modules: user & post

the state structure is a bit like:

{
  user: {
     // oauth access token
     token: 'test'
  },
  post: {
   // ...
  }
}

and the actions also like this.

action post.list => http with headers need Authorization: Bearer 1111111111111111111111111111111111111111 (which is in state.user namespace/scope).

how cloud i fetch it out?

@willin is there an example of how does custom fx works?

From my previous link:

import { withFx } from "@hyperapp/fx"

const state = {
  // ...
}

const actions = {
  /*
    You will probably want to write a helper function for returning these
    similar to the built-in effects
  */
  foo: () => [
    /*
      type of effect for effects data
      must match key used in custom effect object below
    */
    "custom",
    {
      // ... props go here
    }
  ]
}

withFx({
  // key in this object must match type used in effect data above
  custom(props, getAction) {
    /*
      use props to get the props used when creating the effect
      use getAction for firing actions when appropriate
    */
  }
})(app)(state, actions).foo()

@willin the state structure is a bit like:

{
  user: {
     // oauth access token
     token: 'test'
  },
  post: {
   // ...
  }
}

Your user and post are two different state slices that exist independent of each other. You should reorganize your actions so that they are at or above the slice of state they work with.

I recommend you start by building an app without @hyperapp/fx to learn the basics of Hyperapp.

Then ask questions here when something doesn't work that did work using vanilla Hyperapp.