I use redux for react app development. I want to use a reducer to execute some tasks after the mutation completed. Thus, I find it's reasonable to have this feature in react-apollo.
Currently, I have to use then function like this:
createPost({...}).then(res => dispatch(A_Action with res))
I would be great if when I compose the grapql mutation I have the option for setting the action like this:
compose(
graphql(createPost, { name: 'createPost', 'action': 'CREATE_POST_RESULT' }),
...
)(PostForm)
Is there anything wrong with using your own dispatch for this? As you showed in the snippet, it's very little code, and keeps react-apollo simple.
well, I found it too verbose. I need to use this .then(res => dispatch(A_Action with res)) many times. Moreover, I need to pass the dispatch action inside a callback prop most of the time.
Additionally, It would be more readable when I use it only in the compose phase of the container. Don't need to call it via then function in the presentation component. I think it is reasonable right?
Let look at this example:
I have 2 mutations:
Then in the presentational component, I need to add 2 callbacks:
//CompContainer.js
mapDispatchToProps = {
onCreatePostResult: (rs) => {}
onAddCommentResult: (rs) => {}
}
compose(
graphql(createPost, { name: 'createPost' }),
graphql(addComment, { name: 'addComment' }),
...
)(PostForm)
connect(...)
//Comp.js
const Comp = ({onCreatePostResult, onAddCommentResult} => {
...
createPost({...}).then(rs => onCreatePostResult(rs))
addComment({...}).then(rs => onAddCommentResult(rs))
}
Compare to
//CompContainer.js
compose(
graphql(createPost, { name: 'createPost', action: 'CREATE_POST_RESULT' }),
graphql(addComment, { name: 'addComment', action: 'ADD_COMMENT_RESULT' }),
...
)(PostForm)
//Comp.js
const Comp = (() => {
...
createPost({...})
addComment({...})
}
You could put it in the composed container like so:
compose(
connect(),
graphql(createPost, {
name: 'createPost',
props: ({ mutate, dispatch }) => ({
mutate: (...args) => mutate(...args).then(res => dispatch(createAction(res)))
})
)
)(PostForm)
I can see that it does get a bit more verbose then.
You could create your own container that always does the above, as well.
One thing I can see getting complicated is that we then would also have to provide a way for people to set the properties on the action that is dispatched, which would make the whole thing almost as verbose as doing it yourself.
Have you considered using the APOLLO_MUTATION_RESULT action as well?
APOLLO_MUTATION_RESULT is too generic, I need to handle many if else
This snippet could be the stuff that I am looking for.
props: ({ mutate, dispatch }) => ({
mutate: (...args) => mutate(...args).then(res => dispatch(createAction(res)))
})
Many thanks @stubailo
APOLLO_MUTATION_RESULT is too generic
Hmm - it would be like:
if (action.type === 'APOLLO_MUTATION_RESULT' && action.operationName === 'createPost')
I think it should be possible to create a reusable container/utility to get to minimum verbosity as well with the approach of firing a custom action in the HOC, let me know if that would be interesting.
Yes, sure. It will be great if react apollo has one.
@quytang although we use redux under the hood, we don't want react-apollo to be tied to it so we can open up supporting a wide variety of stores in the future.
@stubailo thanks for the great example! Would make for a good recipe
@jacobk @stubailo it seems like dispatch doesn't exist in the props parameter anymore. How can we handle this case at the moment ?
@leizard , i facing the same issue as well, dispatch getting null value.
props: ({ mutate, dispatch }) => ({
deleteInstance: (domain, id) => mutate({ variables: { domain, id } }).then((res) => console.log('dispatch: ', dispatch)),
}),
Anyone kindly provide any advice?
Found the solution.
Avoid perform the mutation in graphql function, instead mutate it in the container.
const { dispatchDeleteInstances } = this.props;
this.props.mutate({ variables: { domain, id } }).then((res) => {
dispatchDeleteInstances();
});
const mapDispatchToProps = (dispatch) => ({
dispatchDeleteInstances: () => dispatch(deleteInstanceAction(),
});
Most helpful comment
You could put it in the composed container like so:
I can see that it does get a bit more verbose then.
You could create your own container that always does the above, as well.
One thing I can see getting complicated is that we then would also have to provide a way for people to set the properties on the action that is dispatched, which would make the whole thing almost as verbose as doing it yourself.
Have you considered using the
APOLLO_MUTATION_RESULTaction as well?