使用RTK查询时,您可以抽象掉数据获取所附带的所有状态管理——您可以调用端点,文档将加载到变量中,随时可以使用。像这样:
const{data:rangesInfo=[]}=useGetRangesQuery(userId(;
假设这个rangesInfo
变量包含一个唯一标识IDuuid
,以及一个指定其位置的数字rangeValue
。这个数字可以从0到100。为了这个例子,让我们想象一下这些范围描述了用户的食物偏好。约翰的寿司得了0分,披萨得了100分。当最终用户点击网站时,他们可以加载其他用户的偏好,因此这组范围不断更新。
这一切都很好——您可以调用rangesInfo.map(range => <RangeComponent key={range.uuid} rangeValue={range.rangeValue}/>)
,这将呈现一组子组件,这些子组件都知道如何显示实际HTMLinput[type=range]
的UI。
但是在React中使用范围滑块输入时,必须在受控输入或非受控输入之间进行选择。React的偏好是输入由其父级的状态控制。在这种情况下,其父级的状态是RTK黑匣子,如果要修改缓存的数据,则必须使其无效,通常通过触发mutation
。这是RTK Query对POST或UPDATE请求的术语,它将影响后端中的数据。问题是,在Chrome中,一个范围输入的onChange
事件每秒触发数十次,当只有最后一个请求起作用时,用40个请求来敲打API似乎很荒谬。
这意味着我们必须使用一个不受控制的组件。当道具发生变化时,问题就变成了更新范围显示。因为道具做了更改——RTK工作正常——但道具不再与范围值的位置有任何关系。(请记住,如果您想通过道具控制输入的值,则不再将您描述为不受控制的组件!(。如果我们能保证每次更换道具时都能重新安装儿童组件,我们应该是清白的,但这不是我的经验。
尽管这些RangeComponents被赋予了唯一的id,即使文档表明这已经足够了,但新数据还是不同步。当我加载页面时,我有用户0的信息,然后我单击用户1,我仍然看到用户0。当我点击User 2时,现在User 1弹出,依此类推。
我最终的破解方案是将ref
附加到输入范围的DOM,然后使用副作用来指定其值,如下所示:
useEffect(((=>{inputRef.current.value=props.rangeValue}(
这解决了我的一致性问题,但给用户体验带来了大量的jank——当我将输入范围设置为新状态时,它会短暂地闪烁回原来的位置。
有没有一种方法可以在保持RTK查询范式的同时解决这个问题?
无jank,无ref的必要解决方案:请特别确保您的子组件的密钥是唯一的,因为RTK将多次重新渲染它,并且渲染;棒";此时可能没有更新的道具。
我的解决方案是将范围的值附加到键上。所以现在代码看起来像:
rangesInfo.map(range => <RangeComponent key={range.uuid + rangeValue} rangeValue={range.rangeValue}/>)
通过将道具和密钥链接在一起,可以保证React将重新安装子组件。
希望这能节省一些时间!