You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React-Apollo中如何在mutation函数外部获取数据?

Fixing Undefined Data in Your GraphQL Mutation Callback

Alright, let's break down why you're hitting that undefined data issue and fix it up. The problem here is that the data variable from the Mutation component's render prop hasn't updated yet when you try to access it in the .then() block—since the mutation is asynchronous, the Mutation component re-renders with the new data after your .then() runs.

Here are a few solid ways to handle this correctly:

1. Access Data Directly from the Mutation Promise Result

The login function returned by the Mutation component resolves to an object containing the mutation result, including the data you need. Instead of relying on the external data variable, grab it from the promise's resolved value:

<Mutation mutation={LOGIN}>
  {(login, { loading, error }) => {
    if (loading) return <h1> Loading... </h1>;
    return (
      <button onClick={e => {
        e.preventDefault();
        login({
          variables: { 
            email: this.state.email, 
            password: this.state.password 
          }
        })
        .then(result => {
          // Get the data from the resolved result object
          const { token, userId, tokenExpiration } = result.data.login;
          this.context.login(token, userId, tokenExpiration);
        })
        .catch(err => {
          // Don't forget to handle errors here!
          console.error("Login failed:", err);
        });
      }}>
        Login
      </button>
    );
  }}
</Mutation>

This is the simplest fix because it uses the direct result of the mutation call, which is guaranteed to have the data once the promise resolves.

2. Use the Mutation Component's onCompleted Prop

If you prefer to keep your click handler clean, you can move the post-login logic to the onCompleted prop of the Mutation component. This callback runs automatically when the mutation succeeds:

<Mutation 
  mutation={LOGIN}
  onCompleted={(data) => {
    const { token, userId, tokenExpiration } = data.login;
    this.context.login(token, userId, tokenExpiration);
  }}
>
  {(login, { loading, error }) => {
    if (loading) return <h1> Loading... </h1>;
    return (
      <button onClick={e => {
        e.preventDefault();
        login({
          variables: { 
            email: this.state.email, 
            password: this.state.password 
          }
        });
      }}>
        Login
      </button>
    );
  }}
</Mutation>

This approach separates concerns—your click handler only triggers the mutation, and onCompleted handles the post-success logic.

3. Pass Data to Parent Components (If Needed)

If you need to share this login data with a parent component, you can pass a callback prop from the parent down to this component. For example:

Parent Component:

class ParentComponent extends React.Component {
  handleLoginSuccess = (token, userId, tokenExpiration) => {
    // Do something with the data in the parent, like updating state
    this.setState({ isLoggedIn: true, userId });
    // Or call context/login here if it's defined in the parent
  };

  render() {
    return <LoginForm onLoginSuccess={this.handleLoginSuccess} />;
  }
}

Your Login Component:

<Mutation mutation={LOGIN}>
  {(login, { loading, error }) => {
    if (loading) return <h1> Loading... </h1>;
    return (
      <button onClick={e => {
        e.preventDefault();
        login({
          variables: { 
            email: this.state.email, 
            password: this.state.password 
          }
        })
        .then(result => {
          const { token, userId, tokenExpiration } = result.data.login;
          // Pass data up to parent via the callback prop
          this.props.onLoginSuccess(token, userId, tokenExpiration);
          // Also call your context login if needed
          this.context.login(token, userId, tokenExpiration);
        });
      }}>
        Login
      </button>
    );
  }}
</Mutation>

This way, you can share the login data with any parent component that needs it.

Quick Note on Error Handling

Don't forget to add error handling either in the .catch() block (if using the promise approach) or by checking the error variable from the Mutation render prop—this will help you debug issues if the mutation fails (like invalid credentials).

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:01:48