为什么apiFetch抛出未处理的承诺拒绝:TypeError:Object不是函数

时间:2020-11-03 作者:philolegein

我正在尝试诊断一个类似的问题this question, 但在这种情况下,他并不依赖wp-api-fetch, 和我很确定我是。

我收到以下错误:

[Error] Unhandled Promise Rejection: TypeError: Object is not a function. (In \'Object(_wordpress_api_fetch__WEBPACK_IMPORTED_MODULE_5__["apiFetch"])\', \'Object\' is an instance of Object)
(完整回溯,如下所示)

我应该注意到,我对RESTAPI和ESNext/Gutenberg插件开发都是新手,所以。。。我可能遗漏了一些非常明显的东西,比如逗号:)

代码如下:

import { __ } from \'@wordpress/i18n\';
import { Fragment } from \'@wordpress/element\';
import { TextControl } from \'@wordpress/components\';
import { apiFetch } from \'@wordpress/api-fetch\';

export default function Edit( props ) {
        const {
                attributes: { cwraggDataSourceType, cwraggDataSource,
                    cwraggLocalFile },
                setAttributes,
        } = props;

        const post_id = wp.data.select("core/editor").getCurrentPostId();

        const onChangeContent = async ( newUrl ) => {
                let localFileName = await apiFetch( {
                    path: \'/cwraggb/v1/setremotedatasrc\',
                    method: \'POST\',
                    data: { \'url\': newUrl,
                            \'type\': \'json\',
                            \'postId\': post_id } } );
                ...
  
        };
        ...
}
我查看了npm run start, 它似乎包括了构建中的依赖项:

<?php return array(\'dependencies\' => array(\'wp-api-fetch\', \'wp-blocks\', \'wp-components\', \'wp-element\', \'wp-i18n\', \'wp-polyfill\'), \'version\' => \'566e4b7cb2f100542103b2b0e25aefae\');

这是在MacOS 10.15.7上构建和运行的docker。

~ % npm --version
6.14.8
~ % wp-env --version
2.1.0
知道是什么导致了错误,和/或我如何进一步诊断?

完整错误消息:

[Error] Unhandled Promise Rejection: TypeError: Object is not a function. (In \'Object(_wordpress_api_fetch__WEBPACK_IMPORTED_MODULE_5__["apiFetch"])\', \'Object\' is an instance of Object)
    dispatchException (wp-polyfill.js:7017)
    invoke (wp-polyfill.js:6738)
    asyncGeneratorStep (cwra-google-graph-block-admin.js:250)
    _next (cwra-google-graph-block-admin.js:272)
    (anonymous function) (cwra-google-graph-block-admin.js:279)
    Promise
    (anonymous function) (cwra-google-graph-block-admin.js:268)
    callCallback (react-dom.js:341)
    dispatchEvent
    invokeGuardedCallbackDev (react-dom.js:391)
    invokeGuardedCallback (react-dom.js:448)
    invokeGuardedCallbackAndCatchFirstError (react-dom.js:462)
    executeDispatch (react-dom.js:594)
    executeDispatchesInOrder (react-dom.js:616)
    executeDispatchesAndRelease (react-dom.js:719)
    forEach
    forEachAccumulated (react-dom.js:699)
    runEventsInBatch (react-dom.js:744)
    runExtractedPluginEventsInBatch (react-dom.js:875)
    handleTopLevel (react-dom.js:6026)
    dispatchEventForPluginEventSystem (react-dom.js:6121)
    dispatchEvent (react-dom.js:6150)
    dispatchEvent
    unstable_runWithPriority (react.js:2820)
    discreteUpdates$1 (react-dom.js:21810)
    discreteUpdates (react-dom.js:2357)
    dispatchDiscreteEvent (react-dom.js:6104)
    dispatchDiscreteEvent

2 个回复
SO网友:Tom J Nowell

根本问题是对异步函数如何工作的误解。

const onChangeContent = async ( newUrl ) => {
onChangeContent 不是函数/异步函数。这是一个目标,特别是一个承诺。

这个asyncawait 都是速记。这两个功能相同:

async function foo() {
   return 1
}

function foo() {
   return Promise.resolve(1)
}
因为React需要一个函数,所以它得到了一个承诺,但失败了。

此外,因为如果apiFetch 调用因任何原因失败,返回的承诺上没有错误处理程序。

不仅如此,代码还被原始放置在React组件中。我强烈建议不要这样做。使用useEffect 相反,如果需要将信息传递回组件,请将其与本地状态相结合。useEffect 在呈现React组件后调用该函数,以便它不会阻止执行。它还可以防止重复不必要的呼叫。

例如,这里我们获取帖子、显示加载状态等:

import React from \'react\';
import apiFetch from \'@wordpress/api-fetch\';
import { useSelect } from \'@wordpress/data\';
import { useState, useEffect, useRef } from \'@wordpress/element\';
import { addQueryArgs } from \'@wordpress/url\';

function PostList() {
    // are we loading the posts?
    const [ isLoading, setLoading ] = useState( true );
    // the posts we\'re displaying
    const [ posts, setPosts ] = useState([]);
    // we don\'t want to update state on an unmounted component
    const isStillMounted = useRef();

    // fetch the posts
    useEffect(() => {
        isStillMounted.current = true;
        apiFetch( {
            path: addQueryArgs( `/wp/v2/posts`, { } ),
        } )
            .then( ( data ) => {
                if ( isStillMounted.current ) {
                    setPosts( data );
                    setLoading( false );
                }
            } )
            .catch( () => {
                if ( isStillMounted.current ) {
                    setPosts( [] );
                    setLoading( false );
                }
            } );
    }, [setPosts, setLoading, isStillMounted]);

    if ( isLoading ) {
        return <div>Loading...</div>;
    }

    return <div>{ .. use posts variable here ... }</div>

}
请记住,这些不是特定于块编辑器的内容,它们是通用的JS React内容。

注意事项:

我们有一个catch 关于apiFetch 调用fetch调用是一种副作用,因此它被移动到useEffect 钩子(hook)

  • 该效果在函数之外所涉及的唯一事情是更新状态,除非3个依赖项发生更改,或者安装了该组件的新实例,否则将不会再次调用该效果添加加载状态useRef 跟踪组件是否已安装。如果在API调用完成之前删除了块,则可以防止出现错误

  • SO网友:philolegein

    虽然我仍然不太了解ESNext/JavaScript,不知道为什么这是答案,但事实证明它确实是;缺少逗号“;类别-具体来说,我无法在导入中使用括号。所以

    import { __ } from \'@wordpress/i18n\';
    import { Fragment } from \'@wordpress/element\';
    import { TextControl } from \'@wordpress/components\';
    import apiFetch from \'@wordpress/api-fetch\';
    
    解决了问题。尽管如此,汤姆的答案也值得一读(包括这个细节)。

    相关推荐

    多国语言上的Gutenberg块JavaScript本地化不起作用

    我可以使用wordpress成功翻译我的插件。org用于所有php字符串。一切都很好。我甚至可以看到需要翻译的字符串https://translate.wordpress.org/projects/wp-plugins/simpletoc/stable/de/default/ 在这种情况下,它是“更新目录”:https://plugins.trac.wordpress.org/browser/simpletoc/tags/1.8/build/index.js#L111所以我翻译了它们,等了24小时。我可以