Bloomca / redux-tiles

Composable way to create less verbose Redux code
https://redux-tiles.js.org/
MIT License
236 stars 10 forks source link

Combining plural and singular async tiles #29

Open danny-does-stuff opened 4 years ago

danny-does-stuff commented 4 years ago

I am seeing the benefit of redux-tiles but I would like some clarification on how to best interact between "plural" and "singular" tiles for the same resource type.

Suppose you want to provide a list of posts for the user. You would create an async tile, posts that can get all posts

const posts = createTile({
    type: ['posts', 'all'],
    fn: async () => api.get('/posts')
})

Now I also want to allow interacting with posts individually. Therefore I would want to create an async tile for that:

const posts = createTile({
    type: ['posts', 'all'],
    fn: async ({params}) => api.get('/posts' + params.id),
    nesting: ({ id }) => [id]
})

The second tile is probably closer to what I actually want, but using the second one I am unable to fetch ALL posts at the same time.

From my components I would like to be able to select either all posts, or a single post depending on my needs, but I can't see a simple way to do this using a single tile.

A possible workaround would be to create a synchronous tile that stores the data, as well as 2 async tiles like the ones above that only put the data into the synchronous tile, something like this

const posts = createSyncTile({
    type: ['posts', 'all']
    fns: {
        setPosts: ({params: posts}) => posts,
        setPost: ({param: post, selectors, getState}) => {
            return {
                ...selectors.posts.all(getState()),
                [post.id]: post,
            }
        }
    },
})

const fetchPosts = createTile({
    type: ['posts', 'fetch'],
    fn: async ({actions, dispatch}) => api.get('/posts').then((posts) => dispatch(actions.posts.all.setPosts(posts)))
})

const fetchPost = createTile({
    type: ['posts', 'fetchOne'],
    fn: async ({actions, dispatch, params: id}) => api.get('/posts/' + id).then((post) => dispatch(actions.posts.all.setPost(post)))
})

But I'm already trying to avoid this boilerplate by using tiles, and it seems like this method is just reintroducing some of that boilerplate code.

@Bloomca If you have any suggestions, I'd be happy to hear. Thanks!