使用apiFetch检索Gutenberg的帖子数据

时间:2021-05-28 作者:leemon

在我正在开发的一个插件中,我注册了一个自定义REST API路由,以获得一些通过post id的post数据:

function rest_api_init() {
    register_rest_route( \'custombase/v1\', \'/post/(?P<id>[\\d]+)\', array(
        \'methods\'             => \'GET\',
        \'callback\'            => \'get_post_rest\',
        \'permission_callback\' => \'__return_true\',
        \'args\'                => array(
            \'id\' => array(
                \'validate_callback\' => function( $param, $request, $key ) {
                    return is_numeric( $param );
                }
            ),
        ),
    ) );
}

function get_post_rest( WP_REST_Request $request ) {
    $post = get_post( $request[\'id\'] );
    if ( is_wp_error( $post ) ) {
        return $post;
    }

    $data = array(
        \'ID\'    => $post->ID,
        \'title\' => $post->post_title,
    );

    $response = new WP_REST_Response( $data, 200 );

    return $response;
}
我已检查,路线已正确注册,因为我可以访问以下URL获取信息:

https://example.com/wp-json/custombase/v1/post/1239
结果如下:

{"ID":1239,"title":"My example post title"}
据我所知,我需要使用apiFetch 用于向古腾堡中的自定义路由发出REST API请求的实用程序。这就是我正在做的:

const mypost = apiFetch( { path: \'custombase/v1/post/1239\' } ).then( ( post ) => {
    return post;
} );
但是,我得到的不是post对象,而是Promise 当我执行console.log( mypost ):

Promise { <state>: "pending" }
​<state>: "fulfilled"
​<value>: Array [ {…} ]
​​0: Object { ID: 1239, title: "My example post title" }
​​length: 1
​​<prototype>: Array []
如何获取post对象?

1 个回复
最合适的回答,由SO网友:Sally CJ 整理而成

我得到一个Promise 当我执行console.log( mypost )

是的,因为apiFetch() 确实返回了Promise 对象,以及apiFetch() 不会将从服务器收到的响应分配给mypost 常量,以及then() 回调也不会分配给mypost 变量

如何获取post对象?

As suggested by React, 您需要添加mypost 作为组件中的本地状态,然后发出XHR/AJAX请求(使用apiFetch(), 本地人window.fetch(), Axios或其他)中的componentDidMount() 类组件的方法,或使用useEffect hook 在功能组件中。

示例使用apiFetch() 具有useEffect:

import { useState, useEffect } from \'@wordpress/element\';
import apiFetch from \'@wordpress/api-fetch\';

function MyComponent( { post_id } ) {
    const [ error, setError ]       = useState( null );
    const [ mypost, setPost ]       = useState( null );
    const [ isLoaded, setIsLoaded ] = useState( false );

    useEffect( () => {
        apiFetch( { path: `custombase/v1/post/${ post_id }` } ).then(
            ( result ) => {
                setIsLoaded( true );
                setPost( result );
            },
            ( error ) => {
                setIsLoaded( true );
                setError( error );
            }
        );
    }, [ post_id ] );

    if ( error ) {
        return <p>ERROR: { error.message }</p>;
    } else if ( ! isLoaded ) {
        return <p>Loading post { post_id }..</p>;
    } else if ( mypost && mypost.id ) {
        return <h3>Post <i>{ mypost.title || \'#\' + mypost.id }</i> loaded!</h3>;
    }
    return <p>No such post</p>;
}
// Sample usage: <MyComponent post_id="1239" />

替代解决方案:将自定义端点的实体添加到块编辑器中的实体列表中addEntities():

import { dispatch } from \'@wordpress/data\';

dispatch( \'core\' ).addEntities( [{
    baseURL: \'/custombase/v1/post\',
    // The \'post\' is not a post type - it\'s the "post" as in /post above. Also, "kind"
    // and "name" are not documented, so let\'s assume they form the above baseURL..
    kind: \'custombase/v1\',
    name: \'post\',
    label: \'Post or whatever\',
}] );

// You can, for example, call the above (i.e. add the entity) before you register your
// block type.
getEntityRecord() 要从终结点获取post数据,请执行以下操作:

const mypost = select( \'core\' ).getEntityRecord( \'custombase/v1\', \'post\', 1239 );
// Note that getEntityRecord() caches the results.
getEntityRecord() 要正常工作,端点回调必须使用小写id 而不是ID:

// In the get_post_rest() function:

$data = array(
    \'id\'    => $post->ID, // use id and *not* ID
    \'title\' => $post->post_title,
);
useSelect, 上述组件(MyComponent) 现在看起来是这样的:

import { useSelect } from \'@wordpress/data\';

function MyComponent( { post_id } ) {
    const { mypost, isLoading } = useSelect( ( select ) => {
        const args = [ \'custombase/v1\', \'post\', post_id ];

        return {
            mypost: select( \'core\' ).getEntityRecord( ...args ),
            isLoading: select( \'core/data\' ).isResolving( \'core\', \'getEntityRecord\', args )
        };
    }, [ post_id ] );

    if ( isLoading ) {
        return <p>Loading post { post_id }..</p>;
    } else if ( mypost && mypost.id ) {
        return <h3>Post <i>{ mypost.title || \'#\' + mypost.id }</i> loaded!</h3>;
    }
    return <p>No such post</p>;
}