如何使用Apollo 2使用GraphQL查询中的数据预填充表单?

时间:2017-12-17 10:48:27

标签: javascript graphql apollo

我很难将Apollo 2 GraphQL查询中的数据转换为常规表单字段。

其他人如何接近这个?以前尝试过Relay,并成功使用组件构造函数设置表单字段状态。

然而,在阿波罗,即使在搜索了几个小时并阅读了大量文档后,我仍然处于黑暗中......

在组件初始化期间,状态始终返回null,因为在稍后阶段设置了props。我试着在加载后设置它,但这让我陷入无休止的循环......

我完全迷失了:/

这就是我现在想出来的......它有效。但这是否是推荐的方法来满足这一要求?

import React from 'react';

import { Route, Redirect, Switch } from "react-router-dom";

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

// SEMANTIC-UI REACT
import { Container, Form, Button, Loader, Message } from "semantic-ui-react";


const MY_QUERY = gql`
  query {
    erp(id:"RXJwTm9kZToy") { 
      id
      name
      code
    }
  }`;


class Test extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
    }
  }

  componentWillReceiveProps(newProps) {
    if (newProps !== this.props) {
      this.setState({
        erp_name: (newProps.data.erp || "").name,
        erp_code: (newProps.data.erp || "").code
      });
    }
  }

  render() {
    if (this.props.data.loading) {
      return <Loader active inline='centered' />;
    } else if (this.props.data.error) {
      return <Message error content={this.props.data.error.message} />;
    } else {
      return (
        <Form>
          <ul>
            <li key={this.props.data.erp.id}>{this.props.data.erp.name}</li>
          </ul>
          <Form.Input name="erp_name" label="ERP Name" placeholder="Name" value={this.state.erp_name} />
          <Form.Input name="erp_code" label="ERP Code" placeholder="Code" value={this.state.erp_code} />
          <Button type='submit'>Submit</Button>
        </Form>
      );
    }
  }
}

export default graphql(MY_QUERY)(Test);

2 个答案:

答案 0 :(得分:0)

这是React和ReduxForm的一个小例子。 也许这会对你有帮助。

在此示例中,查询将在组件初始化时执行,并将返回填写表单所需的数据。

我希望它可以帮到你!

import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { compose } from 'recompose'
import { graphql, withApollo, gql } from 'react-apollo'
import { Form } from 'redux-form'

class MyExampleComponent extends Component {
  render() {
    const { userData } = this.props

    return (
      <Form
        initialValues={userData}
      />
    )
  }
}

MyExampleComponent.propTypes = {
  userData: PropTypes.object
}

const query = gql`
  query getUser($userId: ID) {
    user(id: $userId) {
      age
      firstName
      lastName
    }
  }
`

export default compose(
  withApollo,

  graphql(query, {
    props: ({ data }) => ({
      isLoading: data.loading,
      userData: data.user
    }),
    options: ({ params }) => ({
      variables: { id: params.id }
    })
  })
)(MyExampleComponent)

答案 1 :(得分:0)

我当前使用的方法是始终渲染表单,即使数据尚不可用。这样,由于假定所有数据都可用,因此不需要检查加载道具。如果您确实检查加载道具并仅在数据加载后才呈现表单,则客户端浏览器将等待显示表单,直到数据可用为止,这可能会令人烦恼,尤其是当数据可用时间更长时。最好让浏览器利用这些空闲时间在DOM中建立表单。

但是如何通过graphql查询和预填充了解初始状态?

该状态用于保留表单输入数据,而从未将来自graphql源的初始数据加载到该状态中!每次需要(真实)数据时,都会重新计算。这种重新计算应该只在一个地方发生,因此我引入了一个辅助函数getTruthData()。在任何需要使用真相数据的地方,都可以通过此辅助函数对其进行处理。例如。渲染,并将更新后的数据提交回graphql mutate。而且仅在此getTruthData()函数中,才需要根据可用性返回数据。不必在意性能,因为重新计算真实数据的速度确实非常快,并且由于React重新渲染的特性,缓存只会引入不可预测的结果。

我(已尝试)更新您的代码。我做了什么:

  • 删除componentWillReceiveProps,因为将不再需要
  • 删除要在渲染器中加载的支票
  • 介绍getTruthData()
  • 从不受控制的形式更改为受控制的形式(我后来注意到了,尽管与问题无关)

代码:

class Test extends React.Component {
  constructor(props) {
    super(props);
    this.getProfileTruth = this.getProfileTruth.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  getTruthData() {
    return {
      erp_id: this.props.data.erp.id || '',
      erp_name: this.state.erp_name || this.props.data.erp.name || '',
      erp_code: this.state.erp_code || this.props.data.erp.code || '',
    };

    // OR you might want to use the underscore helper for larger forms with more fields to keep like this:

    return _.defaults(
      {},
      this.state,
      this.props.data.erp,
      { erp_name: '', erp_code: '' },
    );
  }

  handleChange(data) {
    this.setState(data);
  }

  handleSubmit(e) {
    e.preventDefault();
    const { erp_id, erp_name, erp_code } = this.getProfileTruth();
    // run a mutate on graphql
  }


  render() {
    const { erp_id, erp_name, erp_code } = this.getProfileTruth();

    return (
      <Form>
        <ul>
          <li key={erp_id}>{erp.name}</li>
        </ul>
        <Form.Input
          name="erp_name"
          label="ERP Name"
          placeholder="Name"
          value={erp_name}
          onChange={e => this.handleChange({ erp_name: e.target.value })} />
        <Form.Input
          name="erp_code"
          label="ERP Code"
          placeholder="Code"
          value={erp_code}
          onChange={e => this.handleChange({ erp_code: e.target.value })} />
        <Button type='submit' onClick={this.handleSubmit}>Submit</Button>
      </Form>
    );
  }
}

副作用可能是,如果来自graphql的数据要花费很长时间,则该表格已经可以输入。使用受控表单,您可以检入handleChange以仅在正确加载数据时才允许更改。您甚至可以取消激活按钮的样式。