如何在React Apollo 2.1的Mutation组件挂载时执行mutation?
你的直觉是对的——当前if (!called) login();的写法确实存在问题,不符合React的最佳实践,而且可能导致不可预测的行为。让我来解释原因并给出正确的实现方式:
问题所在
- 在React的
render函数中执行副作用(比如调用GraphQL mutation)是违反规则的:render应该是纯函数,只负责根据props和状态返回JSX,不应该产生任何副作用(比如网络请求)。 - 当组件因为props变化或状态更新重新渲染时,这段代码会再次执行,虽然
called状态会阻止重复调用,但如果apiKey发生变化,Mutation组件的variables更新后,called会被重置,导致再次触发mutation(这可能是你需要的,但写法依然不规范)。
正确的实现方式
方式一:使用类组件(兼容React Apollo 2.1及更早版本)
把Authenticator改成类组件,将mutation调用放在生命周期方法中,确保副作用只在合适的时机执行:
import gql from 'graphql-tag'; import React, { Component } from 'react'; import { Mutation } from 'react-apollo'; const AUTH_MUTATION = gql`mutation Login($apiKey: String!) { login(apiKey: $apiKey) { token } }`; export default class Authenticator extends Component { componentDidMount() { // 组件挂载时触发鉴权 this.login(); } componentDidUpdate(prevProps) { // 当apiKey更新时,重新触发鉴权 if (this.props.apiKey !== prevProps.apiKey) { this.login(); } } render() { const { apiKey, render } = this.props; return ( <Mutation mutation={AUTH_MUTATION} variables={{ apiKey }}> {(login, { data, error }) => { // 保存login方法的引用,供生命周期使用 this.login = login; const token = (data && data.login.token) || undefined; return render({ error, token }); }} </Mutation> ); } }
方式二:使用React Hooks(需React 16.8+及对应版本的React Apollo)
如果你的项目已经升级到支持React Hooks的版本,使用useMutation钩子会让代码更简洁:
import gql from 'graphql-tag'; import React, { useEffect } from 'react'; import { useMutation } from 'react-apollo'; const AUTH_MUTATION = gql`mutation Login($apiKey: String!) { login(apiKey: $apiKey) { token } }`; export default function Authenticator({ apiKey, render }) { const [login, { data, error }] = useMutation(AUTH_MUTATION, { variables: { apiKey } }); useEffect(() => { // 组件挂载和apiKey变化时触发鉴权 login(); }, [apiKey, login]); const token = (data && data.login.token) || undefined; return render({ error, token }); }
为什么这两种方式更好?
- 副作用(mutation调用)被放在了React专门处理副作用的生命周期方法(类组件的
componentDidMount/componentDidUpdate)或Hooks(useEffect)中,符合React的设计理念。 - 可以清晰地控制mutation的触发时机:首次挂载时触发,并且当
apiKey变化时自动重新触发,逻辑更清晰。 - 避免了在
render阶段执行副作用可能导致的意外重渲染或其他不可预测的行为。
内容的提问来源于stack exchange,提问作者astorije
相关产品推荐
相关产品推荐

