【问题标题】:Call Typescript Apollo Query from componentDidMount()从 componentDidMount() 调用 Typescript Apollo Query
【发布时间】:2019-10-12 19:00:58
【问题描述】:

我有一个 React 组件,它调用一个期望接收对象数组(用于验证数据)的查询。然后我使用它来验证一个 html 表单,该表单又在 apollo Mutation 元素中定义。它在组件render() 方法的返回语句中的结构方式有效,但看起来很麻烦,它让我想起了回调地狱时代。我真正想要做的是摆脱render() 方法中的<QueryCustomerValidations> 元素并将其移动到(理想情况下)componentDidMount 生命周期事件中。这样验证器就可以在那里加载以供以后在表单中使用,然后留下<MutationCreateCustomer>inside render()。

现在,我必须将表单包装在突变中。查询返回的箭头函数内部的突变,以便以正确的顺序接收异步数据。

    //-------------------------------------------------------------------------
    // Component Lifecycle Eventhandler Methods
    //-------------------------------------------------------------------------
    componentDidMount()
    {

    }    


    //-------------------------------------------------------------------------
    // Render Method Section
    //-------------------------------------------------------------------------
    public render(): JSX.Element
    {
        // Return Form
        return (
            <React.Fragment>
                {/* PAGE TITLE  */}
                <h2 className="text-center mb-3">Agregar Nuevo Cliente</h2>

                {/* LOAD VALIDATIONS INTO STATE  */}
                <QueryCustomerValidations
                    query={Q_GET_CUSTOMER_VALIDATIONS}
                >
                    {({ loading: loadingValidations, error: errorValidations, data: dataValidations }) =>
                    {
                        if (loadingValidations)
                        {
                            return "Cargando..."
                        }
                        if (errorValidations)
                        {
                            return `Error: ${errorValidations.message}`
                        }
                        if (dataValidations)
                        {
                            const validators: ValidationDescriptor[] = []
                            dataValidations.getCustomerValidations.forEach((validator) => {
                                validators.push(validator as ValidationDescriptor)
                            })
                            this.validators.setValidators(validators)
                        }

                        /* DATA ENTRY FORM  */
                        return (
                            <div className="row justify-content-center">

                                <MutationCreateCustomer 
                                    mutation={M_CREATE_CUSTOMER}
                                    onCompleted={() => this.props.history.push('/')}
                                >
                                    {(createCustomer: any) => {
                                        return (                                            
                                            <form name="frmNewCustomer"
                                                    className="col-md-8 m-3"
                                                    onSubmit={e => this.frmNewCustomer_submit(e, createCustomer)}
                                            >

                                                { this.ctrl_form_layout(this.props, this.state, this.validators) }

                                            </form>
                                        )
                                    }}
                                </MutationCreateCustomer>
                            </div>
                        )
                    }}

                </QueryCustomerValidations>

            </React.Fragment>
        );
    }

这里是用于创建查询的接口。由于我使用 apollo 客户端从服务器获取其中一些数据,因此在这种情况下,onDidMount() 上的简单 graphql 查询解决方案将不起作用。

getCustomerValidations.ts (Interfaces)


// ====================================================
// GraphQL query operation: getCustomerValidations
// ====================================================

export interface getCustomerValidations_getCustomerValidations {
  __typename: "ValidationDescriptor";
  field: string | null;
  type: string | null;
  required: boolean;
  max: number | null;
  min: number | null;
  regex: string | null;
}

export interface getCustomerValidations {
  getCustomerValidations: getCustomerValidations_getCustomerValidations[];
}

customer-validations.query.ts (Client side query types)


//---------------------------------------------------------------------------------
// Imports Section (React/Apollo Libs)
//---------------------------------------------------------------------------------
import { gql }                              from 'apollo-boost';
import { Query }                            from 'react-apollo'

import { getCustomerValidations }            from '../../typeDefs/operations/getCustomerValidations'

//---------------------------------------------------------------------------------
// GQL Query: Customers
//---------------------------------------------------------------------------------
export const Q_GET_CUSTOMER_VALIDATIONS = gql`
    query getCustomerValidations {
        getCustomerValidations
        {
            field
            type
            required
            max
            min
            regex
        }
    }
`;

//---------------------------------------------------------------------------------
// Query Class: Customers
//---------------------------------------------------------------------------------
export class QueryCustomerValidations extends Query<getCustomerValidations> { }


正确的解决方案可以是一种从componentDidMount() 方法复制并触发&lt;QueryCustomerValidations&gt;element 的方法,或者如何将元素从render() 方法中取出并像使用某种“等待”的方式,因此可以先调用它,然后再调用突变(并使用查询中的数据)。

谢谢,我知道这个不太容易弄清楚。

【问题讨论】:

    标签: reactjs typescript react-apollo apollo-client react-tsx


    【解决方案1】:

    您正在寻找 hereherehere 描述的“旧”(在 &lt;Query/&gt; 组件之前使用)HOC 模式(带有 compose)。

    将开始时请求的“graphql(gqlquery ...”(无条件 skip 选项)与一个或多个(命名的)“gqlmutation ...”(按需调用)组合在一起,可为您提供清晰易读的解决方案。

    compose(
      graphql(Q_GET_CUSTOMER_VALIDATIONS),
      graphql(gql`mutation { ... }`, { name: 'createSth' })
    )(SomeComponent)
    

    datacreateSth 属性传递给&lt;SomeComponent/&gt; 然后this.props.data 对象将包含loadingerrorgetCustomerValidations 字段/属性。它被描述为here

    查询将在开始时调用(您可以在this.props.data.loading 中期待true),无需在cDM() 运行查询。可以使用 this.props.createSth() 运行突变 - 上面定义的自定义名称(而不是默认的道具名称 mutate)。

    当然,您可以将它们与其他必需的 HOC 混合使用,例如 f.e. redux connect()withFormik() 等 - 只需添加一行代码。

    【讨论】:

    • 是否可以使用graphql(gql query ..." 的方案来加载componentDidMount()中的validators,这样数组就可以被存储并在render()方法中可用?如果那么,请你提供一个如何做到这一点的例子吗?
    • 谢谢,我意识到 HOC 模式可能不是最新的东西,而且我个人不太喜欢这个解决方案,但是因为目前似乎没有更好的方法这个,那么这将是最好的解决方案。也许有一天会有类似&lt;Await&gt;&lt;Query ...&gt;&lt;/Query&gt;&lt;/Await&gt; 这样的代码看起来更干净,我们不需要资源来处理繁琐的模式和结构。
    • 混合?您可以使用带有一个 HOC 的 emhance 组件进行查询(无需撰写),如果您愿意,可以在 render 中使用 &lt;Mutation/&gt; 组件。 Compose 模式可用于更复杂的场景、完整的组件生命周期、额外的内部状态、事件处理程序等。
    • 如果您只需要shortcut,则在“QueryCustomerValidations/>”中覆盖render - 渲染有条件的加载(和错误)并在数据准备好时渲染子级。这样您就可以直接将您的&lt;Mutation/&gt; 包装在一个衬里中。
    猜你喜欢
    • 2021-06-12
    • 2020-12-04
    • 2019-01-25
    • 2019-10-17
    • 2019-10-05
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 2019-03-24
    相关资源
    最近更新 更多