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

Generalising effects/actions/data #36

Closed
RuedigerLudwig opened this issue Dec 3, 2018 · 5 comments
Closed

Generalising effects/actions/data #36

RuedigerLudwig opened this issue Dec 3, 2018 · 5 comments

Comments

@RuedigerLudwig
Copy link

RuedigerLudwig commented Dec 3, 2018

Hello,

first: great and easy to use library. Thank you very much for it

I came along a small problem when trying to reuse my code. I have some state trees, that look very similar to each other. In general they all look the same: Some data, some actions, some selects and some effects. In the effects I need to call actions via the dispatch.

Here the ability to reuse stops, because I need to call the set method with an absolute path and not a relative one. But I might not know in general where and how deep I might be in the "store tree".

Is there an elegant way to solve this?

Cheers
Rüdiger

const store = {
  helper {
    material: {
      list: [],

      ids: select(state => R.pluck('id', state.list)),
      loaded: select(state => state.list === []),

      setList: (state, payload) => {
        return { ...state, list: payload}
      },

      loadAll: effect(async (dispatch, _payload, _getState) => {
        const data = await getAllMaterialien()
        dispatch.helper.material.setList(data) // <<-- I do not know how to generalize this to call this action of my part of the store
      }),
    },
    form: {
      list: [],

      ids: select(state => R.pluck('id', state.list)),
      loaded: select(state => state.list === []),

      setList: (state, payload) => {
        return { ...state, list: payload}
      },

      loadAll: effect(async (dispatch, _payload, _getState) => {
        const data = await getAllFormen()
        dispatch.helper.form.setList(data)
      }),
    },
  },
}
@adrienWeiss
Copy link

adrienWeiss commented Dec 4, 2018

I've been using a function that takes the name and the url to fetch (that would be the function to call for you, getAllMaterialien or getAllFormen) that returns the state tree

{
  [name]: {
    list: [],
    loadAll: effect(...) => {
      ...
      dispatch.helper[name].setList(...
  },
}

and then spreading those

const model = {
  ...materialState,
  ...formState,
},

But I agree with you, one would want to easily parse the local state, but it is also important to be able to dispatch elsewhere.
Also, with the project growing there is a risk of conflicting names.

@ctrlplusb
Copy link
Owner

ctrlplusb commented Dec 6, 2018

@RuedigerLudwig I have opened a PR which may help you with this. Utilising the meta data exposed to the effect function you could do something like:

const list = (endpoint) => ({  
  list: [],
  ids: select(state => R.pluck('id', state.list)),
  loaded: select(state => state.list === []),
  setList: (state, payload) => ({ ...state, list: payload }),
  loadAll: effect(async (dispatch, _payload, _getState, _injections, meta) => {
    const data = await endpoint()
    const setList = R.path(meta.parent.join('setList'), dispatch);
    setList(data);
  }),
})

And then use it like so:

const store = {
  helper: {
    material: {
	  other: '👋',
      ...list(getAllMaterialien)
    },
    form: {
      ...list(getAllFormen)
    },
  },
}

Let me know what you think. 😊

@adrienWeiss - would appreciate your input too.

@ctrlplusb ctrlplusb changed the title Relative Dispatch in Effect Generalising effects/actions/data Dec 6, 2018
@ctrlplusb
Copy link
Owner

The only thing I dislike about this helper approach is that it can be harder to visualise your state tree, however, when the typescript work lands you should get typesafe autocomplete on your model which will help dramatically. :)

ctrlplusb added a commit that referenced this issue Dec 6, 2018
This PR adds a `meta` parameter to effects. This parameter exposes both the parent path and the path of the effect being actioned.

```javascript
const store = createStore({
  foo: {
    doSomething: effect((dispatch, payload, getState, injections, meta) => {
      console.log(meta);
      // {
      //   parent: ['foo'],
      //   path: ['foo', 'doSomething']
      // }
    })
  }
});

await store.dispatch.foo.doSomething()
```

This should open mechanism by which to alleviate issues described within #36.
@ctrlplusb
Copy link
Owner

Available in latest release.

https://github.com/ctrlplusb/easy-peasy/releases/tag/v1.7.0

🤘

@RuedigerLudwig
Copy link
Author

Wow, that is quick. Thank you for the quick addition. I am pretty sure that it solves my use case.

ctrlplusb added a commit that referenced this issue Feb 6, 2019
This PR adds a `meta` parameter to effects. This parameter exposes both the parent path and the path of the effect being actioned.

```javascript
const store = createStore({
  foo: {
    doSomething: effect((dispatch, payload, getState, injections, meta) => {
      console.log(meta);
      // {
      //   parent: ['foo'],
      //   path: ['foo', 'doSomething']
      // }
    })
  }
});

await store.dispatch.foo.doSomething()
```

This should open mechanism by which to alleviate issues described within #36.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants