添加删除按钮

上一部分我们添加了创建新页面的功能,
在这一部分中,我们将添加一个删除功能添加到我们的应用程序中。

以下是我们将要构建的内容:

步骤1:添加删除按钮

让我们从创建删除页面按钮组件和更新我们的用户界面页面列表组件:

从“@wordpress/components”导入{Button};从“@wordpress/html-entities”导入{decodeEntities};const DeletePageButton=()=>(<按钮变量=“primary”>删除</按钮>)函数PagesList({hasResolved,pages}){if(!已解决){return<微调器/>;}if(!页?长度){return无结果;}返回(<table className=“wp-list-table widefat fixed striped table-view-list”><头部><tr><td>标题</td>操作</td></tr></thead><t车身>{pages?.map((page)=>(<tr键={page.id}><td>{decodeEntities(page.title.rendered)}</td><td><div className=“表单按钮”><PageEditButton pageId={page.id}/>{/*这是PagesList组件中的唯一更改*/}<DeletePageButton pageId={page.id}/></div></td></tr>) ) }</tbody></表格>);}

现在PagesList应该是这样的:

步骤2:将按钮关联到删除操作

在古腾堡数据中,我们使用删除实体记录行动。它发送请求,处理结果,并在Redux状态下更新缓存的数据。

以下是您可以尝试在浏览器的开发工具中删除实体记录的方法:

//我们需要一个有效的页面ID来调用deleteEntityRecord,所以让我们使用getEntityRegords获取第一个可用的页面ID。const pageId=wp.data.select('core').getEntityRecords('postType','page')[0].id;//现在,让我们删除该页面:const promise=wp.data.dispatch('core').deleteEntityRecord('postType','page',pageId);//当API请求成功或失败时,promise得到解决或拒绝。

REST API请求完成后,您会注意到其中一个页面已从列表中消失。这是因为该列表由使用选择()钩子和select(coreDataStore).getEntityRecords('postType','page')选择器。每当基础数据发生变化时,列表都会使用新数据重新呈现。那很方便!

让我们在以下情况下执行该操作删除页面按钮单击:

const DeletePageButton=({pageId})=>{const{deleteEntityRecord}=useDispatch(核心数据存储);const handleDelete=()=>删除实体记录('postType','page',pageId);返回(<Button variant=“primary”onClick={handleDelete}>删除</按钮>);}

步骤3:添加视觉反馈

单击删除按钮。让我们用一个<微调器/>组件类似于我们在本教程前几部分中所做的操作。

我们需要正在删除实体记录选择器。它类似于是保存实体记录我们已经在中看到的选择器第3部分:返回真的并且从不发出任何HTTP请求:

const DeletePageButton=({pageId})=>{// ...const{isDeleting}=useSelect(选择=>({isDeleting:选择(coreDataStore).isDeletingEntityRecord('postType','page',pageId),}),[页面ID])返回(<Button variant=“primary”onClick={handleDelete}disabled={isDeleting}>{正在删除吗(<><微调器/>正在删除。。。</>):'删除'}</按钮>);}

下面是实际情况:

步骤4:处理错误

我们乐观地认为删除手术总是会成功的。不幸的是,在后台,它是一个RESTAPI请求,可能会以多种方式失败:

  • 网站可能会关闭。
  • 删除请求可能无效。
  • 在此期间,该页面可能已被其他人删除。

为了告诉用户这些错误何时发生,我们需要使用获取最后一个实体删除错误选择器:

//用实际页面ID替换9wp.data.select('core').getLastEntityDeleteError('postType','page',9)

以下是我们如何将其应用于删除页面按钮:

从'react'导入{useEffect};const DeletePageButton=({pageId})=>{// ...const{错误,/*…*/}=useSelect(选择=>({错误:select(coreDataStore).getLastEntityDeleteError('postType','page',pageId),// ...} ),[页面ID]);使用效果(()=>{if(错误){//显示错误}},[错误])// ...}

这个错误对象来自@wordpress/api-回迁并包含有关错误的信息。它具有以下属性:

  • 消息–人类可读的错误消息,例如帖子ID无效.
  • 代码–基于字符串的错误代码,如rest_post_invalid_id。要了解所有可能的错误代码,您需要参阅/v2/页端点的源代码.
  • 数据(可选)–错误详细信息,包含代码包含失败请求的HTTP响应代码的属性。

有很多方法可以将该对象转换为错误消息,但在本教程中,我们将显示错误消息.

WordPress已经建立了使用小吃店组件。这是它的样子在Widgets编辑器中:

让我们在插件中使用相同类型的通知!这有两个部分:

  1. 显示通知
  2. 正在调度通知

显示通知

我们的应用程序只知道如何显示页面,但不知道如何显示通知。让我们来说说吧!

WordPress方便地为我们提供了呈现通知所需的所有React组件。A类组件名为小吃店表示单个通知:

我们不会使用小吃店不过,这是直接的。我们将使用小吃店列表组件,它可以使用平滑动画显示多个通知,并在几秒钟后自动隐藏它们。事实上,WordPress使用的组件与Widgets编辑器和其他wp-admin页面中使用的组件相同!

让我们创建自己的通知组件:

从“@wordpress/components”导入{SnackbarList};从“@wordpress/notices”导入{store as noticesStore};函数通知(){常量通知=[];//我们马上回来!返回(<小吃店列表通知={notices}className=“components-editor-notices__snackbar”/>);}

基本结构已就位,但它呈现的通知列表为空。我们如何填充它?我们将使用与WordPress相同的软件包:@wordpress/通知.

方法如下:

从“@wordpress/components”导入{SnackbarList};从“@wordpress/notices”导入{store as noticesStore};函数通知(){const通知=使用选择((select)=>select(noticesStore).getNotices(),[]);const{removeNotice}=useDispatch(noticesStore);const snackbarNotices=notices.filter(({type})=>type===“snackbar”);返回(<小吃店列表通知={snackbarNotices}className=“components-editor-notices__snackbar”onRemove={removeNotice}/>);}函数MyFirstApp(){// ...返回(<div>{/* ... */}<通知/></div>);}

本教程的重点是管理页面,不会详细讨论上述代码片段。如果你对@wordpress/通知,的手册页是一个很好的起点。

现在,我们已经准备好告诉用户可能发生的任何错误。

发送通知

有了SnackbarNotices组件,我们就可以发送一些通知了!方法如下:

从'react'导入{useEffect};从“@wordpress/notices”导入{store as noticesStore};函数DeletePageButton({pageId}){const{createSuccessNotice,createErrorNotice}=useDispatch(noticesStore);//如果传递存储句柄,useSelect将返回选择器列表//而不是回调:const{getLastEntityDeleteError}=useSelect(核心数据存储)const-handleDelete=async()=>{const success=等待deleteEntityRecord('postType','page',pageId);if(成功){//告诉用户操作成功:createSuccessNotice(“页面已删除!”{type:“snackbar”,} );}其他{//我们直接使用选择器获取deleteEntityRecord后的新错误//已失败。const lastError=getLastEntityDeleteError(“postType”,“page”,pageId);const message=(lastError?.message | |'出现错误。')+'请刷新页面,然后重试。'//告诉用户操作到底是如何失败的:创建错误通知(消息{type:“snackbar”,} );}}// ...}

伟大的!删除页面按钮现在已完全意识到错误。让我们看看该错误消息的作用。我们将触发一个无效的删除并让其失败。一种方法是将页面ID数量众多:

函数DeletePageButton({pageId,onCancel,onSaveFinished}){pageId=pageId*1000;// ...}

刷新页面并单击任意删除按钮,您应该会看到以下错误消息:

好极了!我们现在可以删除pageId=pageId*1000;行。

现在让我们尝试实际删除一个页面。刷新浏览器并单击“删除”按钮后,您将看到以下内容:

就这样!

将其连接在一起

所有部件都就位了,太棒了!以下是我们在本章中所做的所有更改:

从'react'导入{useState,useEffect};从“@wordpress/data”导入{useSelect,useDispatch};从“@wordpress/components”导入{Button、Modal、TextControl};函数MyFirstApp(){const[searchTerm,setSearchTerm]=使用状态(“”);const{pages,hasResolved}=useSelect((选择)=>{常量查询={};如果(searchTerm){query.search=搜索术语;}const selectorArgs=['postType','page',query];const pages=select(coreDataStore).getEntityRecords(…selectorArgs);返回{页,hasResolved:选择(coreDataStore).hasFinishedResolution('获取实体记录',选择器参数,),};},[searchTerm],);返回(<div><div className=“list-controls”><SearchControl onChange={setSearchTerm}value={searchTerm}/><页面创建按钮/></div><PagesList hasResolved={hasResorved}pages={pages}/><通知/></div>);}函数SnackbarNotices(){const通知=使用选择((select)=>select(noticesStore).getNotices(),[]);const{removeNotice}=useDispatch(noticesStore);const snackbarNotices=notices.filter(({type})=>type=='snackbar');返回(<小吃店列表通知={snackbarNotices}className=“components-editor-notices__snackbar”onRemove={removeNotice}/>);}函数PagesList({hasResolved,pages}){if(!已解决){return<微调器/>;}if(!页?.长度){return无结果;}返回(<table className=“wp-list-table widefat fixed striped table-view-list”><头部><tr><td>标题</td>操作</td></tr></thead><t车身>{pages?.map((page)=>(<tr键={page.id}><td>{page.title.rendered}</td><td><div className=“表单按钮”><PageEditButton pageId={page.id}/><DeletePageButton pageId={page.id}/></div></td></tr>) ) }</tbody></表格>);}函数DeletePageButton({pageId}){const{createSuccessNotice,createErrorNotice}=useDispatch(noticesStore);//如果传递存储句柄,useSelect将返回选择器列表//而不是回调:const{getLastEntityDeleteError}=useSelect(核心数据存储)const handleDelete=async()=>{const success=等待deleteEntityRecord('postType','page',pageId);if(成功){//告诉用户操作成功:createSuccessNotice(“页面已删除!”{type:“snackbar”,} );}其他{//我们直接使用选择器获取此时的错误。//假设我们得到这样的错误://const{lastError}=useSelect(函数(){/*…*/});//那么,在handleDelete中lastError将为null。//为什么?因为我们会引用计算出来的版本//甚至在调用handleDelete之前。const lastError=getLastEntityDeleteError(“postType”,“page”,pageId);const message=(lastError?.message | |'出现错误。')+'请刷新页面,然后重试。'//告诉用户操作到底是如何失败的:创建错误通知(消息{type:“snackbar”,} );}}const{deleteEntityRecord}=useDispatch(核心数据存储);const{isDeleting}=useSelect(选择=>({isDeleting:选择(coreDataStore).isDeletingEntityRecord('postType','page',pageId),} ),[页面ID]);返回(<Button variant=“primary”onClick={handleDelete}disabled={isDeleting}>{正在删除吗(<><微调器/>正在删除。。。</>):'删除'}</按钮>);}

接下来是什么?