Apollo Client 和 Redux 设置导致无限渲染循环
Apollo Client and Redux setup causes infinite render loop
我正在尝试 link 使用 Redux 启动 React Apollo,以便 Apollo 执行查询和变更,并将返回的数据分派到 Redux 存储,以便在应用程序周围分发数据。
我相信我已经接近正确了,但由于某种原因,该应用程序进入了 Redux 调度的无限循环,我不明白为什么。
查看下面的代码:
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);
adminTokensReceived()
动作在 reducer 文件中:
export const adminTokensReceived = tokens => ({
type: 'ADMIN_TOKENS_RECEIVED',
tokens
});
GraphQL 查询仅发送一个网络请求,但控制台显示 ADMIN_TOKENS_RECEIVED
动作不断调度并导致浏览器崩溃。
提前致谢
每当 Apollo HOC 收到新道具时,它都会触发您的操作,这会更新商店并将新道具发送到您的 Apollo HOC,这会导致您的操作触发...
有几种不同的方法可以处理这个问题。在我看来,最直接的方法是放弃 graphql
HOC 并使用 withApollo
代替。类似于:
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 )
}
})
)
上面使用了 recompose 的 lifecycle
,但您可以轻松地将 componentDidMount
方法粘贴到您的组件中。
也就是说,当 Apollo 已经为您存储 GraphQL 查询的结果时,使用 Redux 似乎有点多余。
Apollo 的默认行为是首先从缓存中检索数据,只有在数据不存在时才进行网络请求(这也是为什么您只看到一个网络调用的原因)。这意味着您的应用程序中的任意数量的组件都可以用相同的 graphql
HOC 包装,并且只有第一个要呈现的组件会触发对您的 GraphQL 端点的请求——所有其他组件都会获得它们的 data
来自缓存。
我正在尝试 link 使用 Redux 启动 React Apollo,以便 Apollo 执行查询和变更,并将返回的数据分派到 Redux 存储,以便在应用程序周围分发数据。
我相信我已经接近正确了,但由于某种原因,该应用程序进入了 Redux 调度的无限循环,我不明白为什么。
查看下面的代码:
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);
adminTokensReceived()
动作在 reducer 文件中:
export const adminTokensReceived = tokens => ({
type: 'ADMIN_TOKENS_RECEIVED',
tokens
});
GraphQL 查询仅发送一个网络请求,但控制台显示 ADMIN_TOKENS_RECEIVED
动作不断调度并导致浏览器崩溃。
提前致谢
每当 Apollo HOC 收到新道具时,它都会触发您的操作,这会更新商店并将新道具发送到您的 Apollo HOC,这会导致您的操作触发...
有几种不同的方法可以处理这个问题。在我看来,最直接的方法是放弃 graphql
HOC 并使用 withApollo
代替。类似于:
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 )
}
})
)
上面使用了 recompose 的 lifecycle
,但您可以轻松地将 componentDidMount
方法粘贴到您的组件中。
也就是说,当 Apollo 已经为您存储 GraphQL 查询的结果时,使用 Redux 似乎有点多余。
Apollo 的默认行为是首先从缓存中检索数据,只有在数据不存在时才进行网络请求(这也是为什么您只看到一个网络调用的原因)。这意味着您的应用程序中的任意数量的组件都可以用相同的 graphql
HOC 包装,并且只有第一个要呈现的组件会触发对您的 GraphQL 端点的请求——所有其他组件都会获得它们的 data
来自缓存。