如何避免自定义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
相关产品推荐
相关产品推荐

