繁体   English   中英

如何使用React Apollo 2.1的Mutation组件在mount上运行变异?

[英]How to run a mutation on mount with React Apollo 2.1's Mutation component?

我们目前正在从Relay转向React Apollo 2.1 ,而我正在做的事似乎很可疑。

上下文:只有在用户通过身份验证(通过API密钥)时才能呈现某些组件,因此有一个Authenticator组件可以保护树的其余部分。

App.js ,它被这样使用(显然下面的所有片段都是最小的例子):

import React from 'react';
import Authenticator from './Authenticator';
import MyComponent from './MyComponent';

export default function App({ apiKey }) {
  return (
    <Authenticator apiKey={apiKey}
      render={({ error, token }) => {
        if (error) return <div>{error.message}</div>;
        if (token) return <MyComponent token={token} />;
        return <div>Authenticating...</div>;
      }}
    />
  );
}

如果身份验证成功, MyComponent将被呈现。 Authentication首次渲染/挂载时会将身份验证突变发送到服务器,并相应地调用渲染道具 Authentication.js看起来像这样:

import gql from 'graphql-tag';
import React from 'react';
import { Mutation } from 'react-apollo';

const AUTH_MUTATION = gql`mutation Login($apiKey: String!) {
  login(apiKey: $apiKey) {
    token
  }
}`;

export default function Authenticator({ apiKey, render }) {
  return (
    <Mutation mutation={AUTH_MUTATION} variables={{ apiKey }}>
      {(login, { data, error, called }) => {
        if (!called) login(); // ⚠️ This seems sketchy ⚠️

        const token = (data && data.login.token) || undefined;
        return render({ error, token });
      }}
    </Mutation>
  );
}

if (!called) login(); 是什么让我停下来。 如果我没有指定if (!called) ,UI会变成癫痫并发送数千个请求(这是有道理的,调用login()会导致render()重新运行),但它应该如何使用?

似乎Query组件等效的不同之处在于简单地呈现它发出请求。 我想知道是否有办法将相同的机制应用于Mutation ,这需要调用mutate函数作为渲染道具的一部分。

上面代码段的Relay相当于React Apollo的QueryMutation

// Authentication.js

import React from 'react';
import { graphql, QueryRenderer } from 'react-relay';
import { Environment } from 'relay-runtime';

// Hiding out all the `Environment`-related boilerplate
const environment = return new Environment(/* ... */);

const AUTH_MUTATION = graphql`mutation Login($apiKey: String!) {
  login(apiKey: $apiKey) {
    token
  }
}`;

export default function Authenticator({ apiKey, render }) {
  return (
    <QueryRenderer query={AUTH_MUTATION} variables={{ apiKey }}
      render={render}
    />
  );
}


// App.js

import React from 'react';
import Authenticator from './Authenticator';
import MyComponent from './MyComponent';

export default function App({ apiKey }) {
  return (
    <Authenticator apiKey={apiKey}
      render={({ error, props }) => {
        if (error) return <div>{error.message}</div>;
        if (props) return <MyComponent token={props.loginAPI.token)} />;
        return <div>Authenticating...</div>;
      }}
    />
  );
}

对或错,Apollo对如何使用查询和突变做出一些假设。 按照惯例,查询只会在突变时获取数据,好吧,变异数据。 阿波罗进一步采用这种模式,并假设突变将在某种行动中发生。 因此,就像您观察到的那样, Query在mount上获取查询,而Mutation向下传递一个函数来实际获取突变。

从这个意义上说,你已经偏离了“应该使用这些组件”的方式。

我认为你的方法没有任何直接的错误 - 假设called永远不会被重置,你的组件应该按预期行事。 但是,作为替代方法,您可以创建一个简单的包装器组件来利用componentDidMount

class CallLogin extends React.Component {
  componentDidMount() {
    this.props.login()
  }

  render() {
    // React 16
    return this.props.children
    // Old School :)
    // return <div>{ this.props.children }</div>
  }
}

export default function Authenticator({ apiKey, render }) {
  return (
    <Mutation mutation={AUTH_MUTATION} variables={{ apiKey }}>
      {(login, { data, error }) => {
        const token = (data && data.login.token) || undefined;
        return (
          <CallLogin login={login}>
            {render({ error, token })}
          </CallLogin>
        )
      }}
    </Mutation>
  );
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM