-
Notifications
You must be signed in to change notification settings - Fork 786
Conversation
@@ -0,0 +1,57 @@ | |||
# Design principles of the Apollo Client |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra file!
|
||
const mapStateToProps = ({ foo, baz }) => ({ foo, baz }); | ||
|
||
@ReactReduxConnect(mapStateToProps) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa, what is this decorator magic?? I had no idea you could use react-redux in this way!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah!! Its how we do everything! It's sooooo clean
I went ahead and renamed the repo to |
Here are some thoughts on a slight tweak to the query API and the mutation API. QueriesCurrently the API has a MutationsSimilar to the changes in query, mutations return a dictionary of [key: string]: MutationOptions which is used to bind the resulting props. The prop of each key represents a custom function (with as many args as wanted) which calls client.mutate(options) behind the scenes. The key on the props also represents the state of props in the same shape as the query props ( Added propsSimillar to redux's import { connect } from 'apollo-react';
function mapQueriesToProps({ ownProps, state }) {
return {
category: {
query: `
query getCategory($categoryId: Int!) {
category(id: $categoryId) {
name
color
}
}
`,
variables: {
categoryId: 5,
},
forceFetch: false,
returnPartialData: true,
}
}
}
function mapMutationsToProps({ ownProps, state }) {
return {
addCategory(/* args */) {
return {
mutation: `
mutation postReply(
$topic_id: ID!
$category_id: ID!
$raw: String!
) {
createPost(
topic_id: $topic_id
category: $category_id
raw: $raw
) {
id
cooked
}
}
`,
variables: {
// Use the container component's props
topic_id: ownProps.topic_id,
// Use the redux state
category_id: state.selectedCategory,
// Use an argument passed from the callback
/* args */,
}
};
},
otherAction(controlArg1, controlArg2) {
let mutation = `
mutation postReply(
$topic_id: ID!
$category_id: ID!
$raw: String!
) {
createPost(
topic_id: $topic_id
category: $category_id
raw: $raw
) {
id
cooked
}
}
`
if (controlArg1) {
mutation = `
different mutation
`
}
return {
mutation,
variables: {
// Use the container component's props
topic_id: ownProps.topic_id,
// Use the redux state
category_id: state.selectedCategory,
// Use an argument passed from the callback
/* args */,
}
};
},
}
}
@connect({ mapQueriesToProps, mapMutationsToProps })
class AddCategory extends Component {
onAddCategoryClick(e) {
const { target } = e;
const { addCategory } = this.props;
this.props.addCategory(target.id, target.value);
}
onOtherAction(e) {
const { target } = e;
const { otherAction } = this.props;
this.props.otherAction(target.id, target.value);
}
onCustomComponentMutation(mutation, variables) {
this.props.mutate({ mutation, variables })
.then((graphQLResult) => {
const { errors, data } = graphQLResult;
if (data) {
console.log('got data', data);
}
if (errors) {
console.log('got some GraphQL execution errors', errors);
}
}).catch((error) => {
console.log('there was an error sending the query', error);
});
}
onCustomQuery(query, variables) {
this.props.query({ query, variables })
.then((graphQLResult) => {
const { errors, data } = graphQLResult;
if (data) {
console.log('got data', data);
}
if (errors) {
console.log('got some GraphQL execution errors', errors);
}
}).catch((error) => {
console.log('there was an error sending the query', error);
});
}
render() {
/*
this.props.addCategory is a function that calls a mutation and has the added data of:
{
loading: boolean,
error: Error,
result: GraphQLResult,
}
this.props.categories is a just an object representing the query:
{
loading: boolean,
error: Error,
result: GraphQLResult,
}
*/
}
} Thoughts? cc @johnthepink who built our current react + graphql mixin |
I am interested to see how props that are both a method and data trigger updates on children components. Will If it doesn't I would probably propose That would bring us up to 4 passed props (dispatch, query, mutate, mutations) if mapMutationsToProps is used |
The query stuff looks great. I've been thinking about building in synchronous ways to get initial data into Apollo Client directly, but implementing it in the React container first would be great, and then we can move to the actual feature when it exists. Re: mutations
I think you're right that putting the props on a function is a bit odd. Perhaps we have an extra option in So like: function mapMutationsToProps({ ownProps, state }) {
return {
addCategory(/* args */) {
return {
mutation: `...`,
variables: {...},
statusProp: 'addCategoryStatus',
};
},
}
}
// In the component
this.props.addCategoryStatus.loading Although, I'm also OK with your proposed design! Up to you. Re: added props I think this is a great idea! |
@stubailo thanks for the feedback! I should have this done tomorrow! I've also got to make the component not require a redux store. I'll open a PR to the docs repo once this is merged. |
Design implementation is in the README. 🎉
We need to go ahead and setup CI / Coverage and the deps on apollo-client will need to be updated after the next publish.
This needs more tests too, but all functionality should be there so we can start using it while I back test all of it
cc @johnthepink @stubailo