构建具有明确状态所有权的 React 搜索界面
构建一个React搜索界面,使事件、派生值、请求生命周期和结果展示相互独立,从而确保返回的答案与查询内容匹配。
搜索后端虽然能够找到正确的文档,但仍可能带来混乱的用户体验。早期查询的缓慢响应可能会覆盖掉最新的结果,筛选条件计数也可能落后于列表内容,而来源面板则可能显示之前答案中的引用信息。
这些问题的根源往往在于职责不清:多个状态变量代表着相同的事实,或者某些效果会推断出界面已经处理过的事件。
对于基于 React 的知识应用,首先需要明确每个值的含义以及哪些操作可以修改它们。
将输入内容与提交的查询分开
搜索框中的当前文本与显示答案所对应的查询是两回事。用户可以在查看之前的结果时编辑输入内容。
明确体现这种差异。保留草稿输入、提交的查询或请求标识以及最终的请求状态。结果应包含其所回答的查询内容。
对于基于提交的搜索,提交处理程序已经知道有搜索请求发生,可以直接调用相关操作。仅仅为了让某个效应能够感知到这一情况而设置布尔值,只会增加额外的状态转换,却无法明确工作流程。
实时搜索则有不同的要求:结果需要跟踪不断变化的查询。可以由查询层或具有明确生命周期的效应来负责这种同步处理。应先确定行为逻辑,再确定实现边界。
推导无需独立存储的值
如果结果数量来自可见数组,那就直接从该数组计算。同时存储数组和单独更新的计数值,会导致两个数值可能出现不一致。
由当前状态和简单的客户端过滤机制生成的标签也是如此。将一个 React 值复制到另一个值中的情况,往往表明应该让第二个值通过计算得出。
这并不意味着所有的本地状态都是多余的。可编辑的草稿可以有意与服务器数据有所不同。关键在于明确何时可以用新的服务器值替换用户的工作成果。
为异步操作指定明确的负责人
假设有两个提交的请求。请求 A 先开始,请求 B 后开始,且 B 更先完成。如果之后 A 无条件地替换了结果,屏幕上显示的就会是错误问题的答案。
将结果与请求标识关联起来。只有当前活跃的请求才能替换现有的结果。在传输机制支持取消操作时,应取消过时的任务,同时也要处理先前任务可能已完成的情况。
查询层可以提供这些功能,或者专门的请求控制器也可以实现它们。该组件应使用明确的状态,如空闲、加载中、成功或错误,而非通过协调一系列依赖关系来触发下一步操作。
订阅、定时器以及浏览器监听器仍然需要进行生命周期清理。应将某个操作视为对外部同步过程的掌控,其设置与清理应当相互配合、逻辑一致。
将证据附在对应答案上
将答案及其来源引用作为与提交查询相关的单一响应返回。当有效结果发生变化时,需同步更新这些内容。
一个有用的来源引用应包含稳定的来源标识符以及段落位置。来源质量工作流程解释了为何仅标题是不够的。如果应用支持证据预览,需保持每个显示的主张与用于证明它的段落之间的对应关系。
需要将空结果与未得到回答的问题以及请求失败的情况区分开来。即便这三种情况都会导致列表为空,但它们对用户而言意味着不同的后续操作。
在不利时间条件下测试交互功能
快速提交两个问题,但让第一个请求的处理速度变慢。在请求进行中可更改筛选条件。在请求完成前离开页面。出错后重新尝试。检查答案、查询标签及来源面板是否保持一致。
这些情况将RAG评估延伸到了界面层面。只有当用户能看到与其实际请求的答案相关的证据时,证据的质量才有意义。