【问题标题】:React Apollo: Uncaught (in promise) TypeError: Cannot read property 'refetch' of undefinedReact Apollo:未捕获(承诺中)TypeError:无法读取未定义的属性“重新获取”
【发布时间】:2020-06-17 13:30:39
【问题描述】:

我有一个函数,其中包含一些承诺链,但这不是重点。

当我运行某个突变的refetch 时,它给了我Uncaught (in promise) TypeError: Cannot read property 'refetch' of undefined

奇怪的是,如果我在它之前删除一个突变,它就会起作用。代码如下:

Promise.all(this.props.questionnaireData.map(({ kind, id }): Promise<any> => {
    const responses = this.props.formData[kind];
    return this.props.updateQuestionnaire(id, responses);
})).then(() => {
    this.props.finishAssessment(this.props.assessmentId)
        .then(() => {
            track('Assessment -- Finished', {
                'Assessment Kind' : this.props.assessmentKind,
                'Assessment Id'   : this.props.assessmentId,
            });
            if (this.props.assessmentKind === 'INITIAL_ASSESSMENT') {
                this.props.getCompletedInitialAssessment.refetch().then(() => {
                    Router.replace(routes.LoadingAssessmentResults.to, routes.LoadingAssessmentResults.as);
                });

                this.submitEmailNotifications();
            } else if(this.props.assessmentKind === 'GOAL_CHECK_IN') {
                Router.replace(routes.MemberProgressDashboard.to, routes.MemberProgressDashboard.as);
            } else {
                Router.replace(routes.MemberDashboard.to, routes.MemberDashboard.as);
            }
        });
});

错误发生在this.props.getCompletedInitialAssessment.refetch(),我不知道为什么。但是,当我删除 this.props.finishAssessment(this.props.assessmentId) 时,只有这样才能重新获取。

基本上:

Promise.all(this.props.questionnaireData.map(({ kind, id }): Promise<any> => {
    const responses = this.props.formData[kind];
    return this.props.updateQuestionnaire(id, responses);
})).then(() => {
        track('Assessment -- Finished', {
            'Assessment Kind' : this.props.assessmentKind,
            'Assessment Id'   : this.props.assessmentId,
        });
        if (this.props.assessmentKind === 'INITIAL_ASSESSMENT') {
            this.props.getCompletedInitialAssessment.refetch().then(() => {
            Router.replace(routes.LoadingAssessmentResults.to, routes.LoadingAssessmentResults.as);
            });

            this.submitEmailNotifications();
        } else if(this.props.assessmentKind === 'GOAL_CHECK_IN') {
            Router.replace(routes.MemberProgressDashboard.to, routes.MemberProgressDashboard.as);
        } else {
            Router.replace(routes.MemberDashboard.to, routes.MemberDashboard.as);
        }
});

将使重新获取工作。否则它会抱怨它不知道 refetch 是什么。

对于 Apollo,我使用的是 graphql HOC,它看起来像这样:

graphql(getCompletedInitialAssessment, {
    name    : 'getCompletedInitialAssessment',
    options : { variables: { status: ['Finished'], limit: 1 } },
}),
graphql(updateQuestionnaire, {
    props: ({ mutate }) => ({
        updateQuestionnaire: (id, responses) => {
            let normalized = {};

                for (let res in responses) {
                    let num = +responses[res];
                    // If the value is a stringified numuber, turn it into a num
                    // otherwise, keep it a string.
                    normalized[res] = Number.isNaN(num) ? responses[res] : num;
                }

                const input = {
                    id,
                    patch: { responses: JSON.stringify(normalized) },
                };

                return mutate({
                    variables: { input },
                });
            },
        }),
    }),
graphql(finishAssessment, {
    props: ({ mutate }) => ({
        finishAssessment: (id) => {
            const input = { id };

            return mutate({
                variables      : { input },
                refetchQueries : ['getMemberInfo'],
            });
        },
    }),
}),

我尝试过甚至重写它以使用 async/await,但问题仍然存在:

try {
    await Promise.all(this.props.questionnaireData.map(({ kind, id }): Promise<any> => {
        const responses = this.props.formData[kind];
        return this.props.updateQuestionnaire(id, responses);
    }));
    const finishAssessmentRes = await this.props.finishAssessment(this.props.assessmentId);
    console.log(finishAssessmentRes)

    if (this.props.assessmentKind === 'INITIAL_ASSESSMENT') {
        const res = await this.props.getCompletedInitialAssessment.refetch();
        console.log(res);
        this.submitEmailNotifications();
        Router.replace(routes.LoadingAssessmentResults.to, routes.LoadingAssessmentResults.as);
    } else if(this.props.assessmentKind === 'GOAL_CHECK_IN') {
        Router.replace(routes.MemberProgressDashboard.to, routes.MemberProgressDashboard.as);
    } else {
        Router.replace(routes.MemberDashboard.to, routes.MemberDashboard.as);
    }
} catch (error) {
    console.error(error);
}

老实说,我不知道发生了什么,也不知道为什么 refetch 不起作用。重构为钩子会有帮助吗?有人知道吗?

【问题讨论】:

  • 该错误实际上与重新获取无关,它告诉您没有this.props.getCompletedInitialAssessment 可以调用重新获取。
  • 可以理解。我不知道为什么会在调用 finishAssessment 后发生这种情况。它会覆盖getCompletedInitialAssessment吗?
  • 好吧,我假设getCompletedInitialAssessment 是作为prop 传递给组件的父状态的一部分?它是如何改变的?什么时候?你知道设置状态是异步的吗?

标签: javascript reactjs graphql react-apollo


【解决方案1】:

来自the docs

config.props 属性允许您定义一个映射函数,该函数采用由graphql() 函数添加的道具...(props.data 用于查询,props.mutate 用于突变)并允许您计算新的道具...对象将提供给graphql() 正在包装的组件

要访问不是由graphql() 函数添加的道具,请使用ownProps 关键字。

通过使用props 函数,您可以告诉 HOC 哪些道具要传递给下一个 HOC 或组件本身。如果您在 props 中返回的内容中不包含已经传递给它的 props,则它不会传递给组件。你需要为每个props 函数做这样的事情:

props: ({ mutate, ownProps }) => ({
  finishAssessment: (id) => {
    //
  },
  ...ownProps,
}),

编写 HOC 是一件痛苦的事,无论如何,graphql HOC 已被弃用,取而代之的是钩子。我强烈建议迁移到 hooks API。

【讨论】:

  • 不幸的是,这不起作用,但我认为迁移到钩子是正确的。我将尝试在宏伟的计划中做到这一点。
猜你喜欢
  • 1970-01-01
  • 2019-05-16
  • 2018-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-24
  • 2017-03-04
  • 1970-01-01
相关资源
最近更新 更多