Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to run an action from outside a connected component #76

Open
codeincontext opened this issue Feb 20, 2018 · 5 comments
Open

How to run an action from outside a connected component #76

codeincontext opened this issue Feb 20, 2018 · 5 comments
Labels

Comments

@codeincontext
Copy link

Similar to #75

You sometimes need to run an action from outside a connected component. I haven't seen a recommended pattern to do this so have come up with a temporary solution

This is basically mapActions but scoped to the current module's actions

export function bindActions(store) {
  const innerActions = actions(store);
  let mapped = {};
  for (let i in innerActions) {
    mapped[i] = store.action(innerActions[i]);
  }
  return mapped;
}

// usage
bindActions(store).setActiveOrder(order);

This also works, but uses a string to reference the action name

export const runAction = (store, actionName, args) => store.action(actions(store)[actionName])(args);

// usage
runAction(store, 'setActiveOrder', order);

Any thoughts on a nice way to do this?

@ehaynes99
Copy link

Agreed. I wish mapActions were exposed directly, but I did something like your first, but instead of current module's actions, taking both state and actions as parameters to make it reusable.

@developit
Copy link
Owner

developit commented Apr 27, 2018

Might be worth taking a peek at Stockroom. It extends Unistore with this functionality in order to make actions centralized (since they're running in a single Web Worker).

The key is to replace store.action() with an implementation that pulls actions by name rather than expecting a mapping/mapping function.

@developit
Copy link
Owner

It seems like we have a fairly decent surface area for this already. Most notably, it's a bit hard to provide a simple API for bindActions, since it requires a Store reference due to the store not being a singleton.

I tend to use things like your example above, or just throw the .action() call inline:

import { add, subtract } from './actions';

store.setState({ value: 5 })
store.action(add)(5)
store.getState().value // 10

@Birch-san
Copy link

Birch-san commented Mar 14, 2019

The following is not really a 'pattern' as such, but it's certainly a simple way that's supported well by the API:

const store = createStore({
  lols: 5,
});

const actions = (store) => ({
  myCoolAction(state) {
    return { ...state, lols: state.lols+1 }
  },
});

store.setState(actions(store).myCoolAction(store.getState()));

@Birch-san
Copy link

Here's the pattern I settled on:

const store = createStore({
  ready: false,
  lols: 5,
});

const actions = (store) => ({
  increment(state) {
    return {...state, lols: state.lols+1 }
  },
  setReady(state, ready) {
    return {...state, ready: ready, }
  },
});

function act(store, actionsObj, action, ...args) {
  return store.setState(
    actionsObj[action](
      store.getState(),
      ...args));
}
const actor = act.bind(null, store, actions(store));
const boundActions = Object.assign({}, 
  ...Object.keys(actions(store))
    .map(action => ({
      [action]: actor.bind(null, action),
    })),
);

boundActions.increment();
boundActions.setReady(true);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants