I have a similar experience. I’ve started project with Apollo client and it all worked well at the beginning. But soon I figured out that components became overcomplicated.
Especially you can feel it when your business action can contain many operations — like one mutation can generate another or you have to update Apollo cache after mutation and it’s not straightforward.
Apollo simplifies a lot of things. But at the same time, it tries to solve 3 problems and mix it all together:
- business logic
- communication with backend
- state management
I came up to the conclusion that 3 different tools will work better
- redux-saga
- apollo client
- redux
export default class PostsList extends Component<IProps> {
componentDidMount(): void {
this.props.loadPosts();
} render() {
const { posts, loading } = this.props;
if (loading) return <Loading /> return (
<div>
{posts.map((post: Post) => (
<div>
<h4>{post.title}</h4>
<Button onClick={() => this.props.deletePost({id: post.id})}>
Delete
</Button>
</div>
))}
</div>
);
}
}
the visual component doesn’t know what happens behind the savePost
— keep our components small and simple. Move logic to redux-saga
function* loadPosts(action: ILoadPostsAction) {
const result = yield apolloClient.query({
query: loadPosts,
variables: { ... },
fetchPolicy: "no-cache"
});
yield put(savePosts(result.data.posts)); // save to state
};
function* deletePost(action: IDeletePostAction) {
try {
yield apolloClient.mutate({
mutation: deletePost,
variables: { id: action.id }
});
} catch (errors) {... }
yield put(loadPosts());
}
// reducer will read with savePosts