You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何避免自定义WordPress Gutenberg区块重复发起AJAX请求

解决方案

问题1:输入单个字符触发API请求

原代码中withSelect会在articleId每次变化时自动执行,导致每输入一个字符就遍历所有文章类型并发起请求。要避免这种无意义的频繁请求,应该改为手动触发校验(比如点击按钮),而非自动触发。

问题2:按钮点击首次返回undefined

getEntityRecord是同步选择器,直接调用只会返回当前缓存的数据,当API请求还在进行时会返回undefined。正确做法是使用resolveSelect获取异步Promise,等待请求完成后再判断结果;同时要注意重置校验状态,避免旧数据干扰。

修正后的完整代码

export default function (blocks, components, data, compose) {
    const { registerBlockType } = blocks;
    const { TextControl, SelectControl, Button } = components;
    const { withSelect, withDispatch } = data;

    const ArticleBlock = (props) => {
        const { attributes, setAttributes, postTypes, resolveSelect } = props;
        const { articleId, articleExists, style } = attributes;

        const styles = [
            { value: 'simple', label: 'Simple' },
            { value: 'thumbnail', label: 'Thumbnail' },
        ];

        // 输入ID时重置校验状态,避免旧结果残留
        const handleArticleIdChange = (value) => {
            setAttributes({ 
                articleId: value,
                articleExists: false
            });
        };

        const checkArticleExists = async () => {
            if (!articleId) return; // 空ID不触发校验

            let exists = false;
            if (postTypes) {
                for (const postType of postTypes) {
                    try {
                        // 使用resolveSelect等待API请求完成,获取真实结果
                        const post = await resolveSelect('core').getEntityRecord('postType', postType.slug, articleId);
                        if (post) {
                            exists = true;
                            break;
                        }
                    } catch (error) {
                        console.error('Error fetching article:', error);
                    }
                }
            }
            setAttributes({ articleExists: exists });
        };        

        return (
            <div>
                <TextControl
                    label="Article ID"
                    value={articleId}
                    onChange={handleArticleIdChange}
                />
                <Button 
                    text="Check Article Existence"
                    className="btn btn-primary btn-sm pb-2"
                    onClick={checkArticleExists}
                    disabled={!articleId} // 空ID时禁用按钮,防止无效请求
                />
                {articleId && (
                    <p>{articleExists ? 'Article exists' : 'Article does not exist'}</p>
                )}
                <SelectControl
                    label="Style"
                    value={style}
                    options={styles}
                    onChange={(value) => setAttributes({ style: value })}
                />
                {style === 'simple' && <p>Display Simple Style: Title Only</p>}
                {style === 'thumbnail' && <p>Display Thumbnail Style: Featured Image and Title</p>}
            </div>
        );
    };

    registerBlockType('cs/highlighted-article', {
        title: 'CS: Highlighted Article',
        icon: 'admin-post',
        category: 'common',
        attributes: {
            articleId: {
                type: 'string',
                default: '',
            },
            articleExists: {
                type: 'boolean',
                default: false,
            },
            style: {
                type: 'string',
                default: 'simple',
            }
        },
        edit: compose.compose(
            withSelect((select) => {
                const postTypes = select('core').getPostTypes({ per_page: -1 });
                return { postTypes };
            }),
            withDispatch((dispatch) => {
                return {
                    resolveSelect: dispatch.core.resolveSelect,
                };
            })
        )(ArticleBlock),
        save: ({ attributes }) => {
            const { articleId, style } = attributes;
    
            return (
                <>
                  <div data-cs-highlighted-article data-article-id={articleId} data-style={style}></div>
                </>
            );
        },
    });
};

关键修正点

  • 用withDispatch获取resolveSelect,它会返回Promise,等待API请求完成后返回真实结果,解决首次点击返回undefined的问题。
  • 新增handleArticleIdChange方法,修改ID时自动重置校验状态,避免旧结果误导用户。
  • 按钮添加disabled属性,空ID时禁止点击,减少无效请求。
  • 移除冗余的articleFound属性,简化状态管理逻辑。

可选优化:防抖自动校验

如果不想依赖按钮,希望用户输入完成后自动校验,可以添加防抖函数(延迟执行请求,避免频繁触发):

// 导入lodash防抖工具(或自行实现防抖函数)
import { debounce } from 'lodash';

// 在组件内部定义防抖校验函数
const debouncedCheck = React.useMemo(() => 
    debounce(checkArticleExists, 500), 
    [articleId, postTypes]
);

// 修改TextControl的onChange逻辑
<TextControl
    label="Article ID"
    value={articleId}
    onChange={(value) => {
        setAttributes({ articleId: value });
        debouncedCheck();
    }}
/>

注:使用React hooks需确保组件为函数组件,或用useMemo避免防抖函数重复创建。

内容的提问来源于stack exchange,提问作者Free Lancer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 04:34:53