unistore icon indicating copy to clipboard operation
unistore copied to clipboard

Show how to reuse actions within actions in docs?

Open jaredpalmer opened this issue 6 years ago • 4 comments

This works... maybe worth adding to the readme.

// If actions is a function, it gets passed the store:
let actions = store => ({
  // Actions can just return a state update:
  increment(state) {
    return { count: state.count + 1 };
  },
   // The above example as an Arrow Function:
  increment2: ({ count }) => ({ count: count + 1 }),

  // Async actions are actions that call store.setState():
  incrementAsync(state) {
    store.setState(this.increment(state));
    setTimeout(() => {
      store.setState({ count: store.getState().count + 1 });
    }, 1000);
  },
});

jaredpalmer avatar Feb 13 '18 16:02 jaredpalmer

Hmm i tried that, but my this is bound to onClick if we refer to the example in the README.

edit and binding each function to actions object for correct context seems a bit tedious, it would be nice if it was passed in as parameter al la FormidableLabs/freactal where they are called effects

davidchase avatar Feb 28 '18 18:02 davidchase

@jaredpalmer Your async action increments the count twice, FYI.

@davidchase Binding of this is a flaw in the javascript language, not unistore. You can just initialize all the actions as pure functions and return and object that references them so you're not using this for anything. E.g.

export default (store) => {
  const increment = (state) => {
    return {
      count: state.count + 1,
    }
  }

  const incrementAsync = (state) => {
    setTimeout(() => {
      store.setState(increment(state))
    }, 1000)
  }

  return {
    increment,
    incrementAsync,
  }
}

ehaynes99 avatar Apr 03 '18 20:04 ehaynes99

Might be worth changing the readme to more explicitly spell out the outer function and calling contexts:

// If actions is a function, it gets passed the store:
function createActions(store) {
  const actions = {
    // Actions can just return a state update:
    increment(state) {
      return { count: state.count + 1 };
    },
     // The above example as an Arrow Function:
    increment2: ({ count }) => ({ count: count + 1 }),

    // Async actions are actions that call store.setState():
    incrementAsync(state) {
      store.setState(actions.increment(state));
      setTimeout(() => {
        store.setState({ count: store.getState().count + 1 });
      }, 1000);
    }
  };

  return actions;
}

Otherwise I'd recommend something like what @ehaynes99 suggested - avoid context entirely.

developit avatar Apr 27 '18 02:04 developit

I'm trying to avoid the wrapping/context to have my actions.js be a collection of pure functions but it makes hard to have a "thunk" like functionality. How can I achieve something like the following without having to import the store into actions.js and without wrapping actions into a context/function?

const setName = (state, name) => {
  state.name = name;
  validateName(state, name); //async but nobody will get this state update?
  return state:
};

const validateName = async (state, name) => {
   const isValid = await ... // axios stuff...
   state.nameIsValid = isValid;
   return state; // wait! this state is STALE, because I'm returning an old version of state
};

damianobarbati avatar Apr 19 '19 09:04 damianobarbati