Reputation: 2018
I'm trying to link up React Apollo with Redux so Apollo performs the queries and mutations, and the returned data is dispatched to the Redux store in order to distribute the data around the app.
I believe I'm close to getting it right, but for some reason the app goes into an infinite loop of Redux dispatches, and I can't figure out why.
See code below:
class Admin extends Component {
constructor(props) {
super(props);
}
render({
adminAllTokens
}, {}) {
return ( /* JSX */ )
);
}
}
const AllRefreshTokens = gql `
query {
allUsers {
refreshToken
email
}
}
`;
const gqlWrapper = graphql(AllRefreshTokens, {
props: ({
ownProps,
data
}) => {
ownProps.receivedAdminTokens(data.allUsers); //dispatch to Redux store
return {
...data,
gqladminAllTokens
};
}
});
function mapStateToProps(state, ownProps) {
return {
adminAllTokens: state.auth.adminAllTokens
};
}
function mapDispatchToProps(dispatch) {
return {
receivedAdminTokens: tokens => {
dispatch(adminTokensReceived(tokens));
}
};
}
const reduxWrapper = connect(mapStateToProps, mapDispatchToProps);
export default compose(reduxWrapper, gqlWrapper)(Admin);
The adminTokensReceived()
action is in the reducer file:
export const adminTokensReceived = tokens => ({
type: 'ADMIN_TOKENS_RECEIVED',
tokens
});
The GraphQL query only sends one network request, but the console is showing the ADMIN_TOKENS_RECEIVED
action dispatching constantly and crashes the browser.
Thanks in advance
Upvotes: 1
Views: 1350
Reputation: 84687
Whenever the Apollo HOC receives new props, it causes your action to fire, which updates the store and sends new props to your Apollo HOC, which causes your action to fire...
There's a couple of different ways you could handle this. In my mind, the most straightforward would be to drop the graphql
HOC and use withApollo
instead. Something like:
compose(
withApollo,
connect(mapStateToProps, mapDispatchToProps)
lifecycle({
componentDidMount() {
const { client } = this.props
client.query({ query: AllRefreshTokens })
.then(({data}) => {
receivedAdminTokens(data.allUsers)
})
.catch( //any error handling logic )
}
})
)
The above uses recompose's lifecycle
but you could just as easily stick the componentDidMount
method inside your component.
That said, it seems a little redundant to use Redux to store the results of your GraphQL queries when Apollo already does it for you.
Apollo's default behavior is to retrieve the data from the cache first, and only make a network request if the data doesn't exist (which is also why you only saw the one network call). That means any number of components inside your app could be wrapped with the same graphql
HOC, and only the first component to be rendered would trigger a request to your GraphQL endpoint -- all other components would get their data
from the cache.
Upvotes: 1