javascript - 在传递给 RxJS 订阅的回调中使用来自 useState 钩子的 React setState 会导致异常
问题描述
我正在编写一些帮助程序来简化 React 中 RxJS 的使用。
我编写了一个自定义钩子,它允许您发送回调以订阅并从 RxJS 流中获取更新并更新它。这个钩子还允许您为流错误和完成注册回调。这些在测试中正常工作,但是在编写适当的示例时,React 会在流错误上抛出错误,应该处理的错误以及在 UI 中显示的消息。
这是一个与下面代码相同的工作沙箱,带有用于更新、发送错误和完成流的按钮
演示组件如下。请注意发生错误的行:
export default ({subject})=>{
const [hasError, setHasError] = useState(false);
const [complete, setComplete] = useState(false);
const onError = (err)=>{
setHasError(true); // <-------------- Commenting this line avoids the error!
console.log('Value handled error',err);
};
const onComplete = ()=>{
setComplete(true);
console.log('Value handled completion');
};
const [val,setVal] = useSubject(subject,onError,onComplete);
const onClick = ()=>setVal(val+1);
return (
<span>
{val}
{hasError?' An Error ocurred ':null}
{complete?' Stream has completed ':null}
<button onClick={onClick}>increment</button>
<button onClick={()=>subject.error(5)}>Generate error</button>
<button onClick={()=>subject.complete()}>Complete</button>
</span>
);
}
自定义钩子如下:
export const useSubject = (subject,onError,onComplete) => {
const [value, setValue] = useState(subject.getValue());
useEffect(() => {
const subFn = { next: data => setValue(data) };
if (onError) { subFn.error = err => onError(err); }
if (onComplete) { subFn.complete = () => onComplete(); }
const sub = subject.pipe(skip(1)).subscribe(subFn);
return () => sub.unsubscribe();
});
const newSetState = state => subject.next(state);
return [value, newSetState];
};
来自 React 的错误消息不是很有用,如果我理解正确,错误边界只会帮助我显示更好的 UI,但我有兴趣修复错误,而不是包含它。
随着更新状态的行被注释掉,回调工作并没有问题地记录到控制台,而如果我在回调中更新状态(所以我可以驱动 UI 更新),它会崩溃。我尝试了许多解决方法并在钩子和组件之间转移责任,但最后我确实需要在组件中更新状态,这会导致崩溃。奇怪的是,完成流也会通过一个非常相似的回调来更新状态,但那是有效的。
我究竟做错了什么?它可以得到帮助或解决吗?
解决方案
在 RxJS 中,任何错误或完整调用基本上都会“杀死”一个流。在您setHasError(true)
进入“示例”组件后,它会重新渲染并再次运行此行:
const [val, setVal] = useSubject(subject, onError, onComplete);
该钩子以:
const [value, setValue] = useState(subject.getValue());
错误主题上的 getValue() 会引发错误。
推荐阅读
- python - Python dash - 如何突出显示/加粗一行中的特定单词
- pymongo - pymongo:文档必须是 dict 的实例
- reactjs - 如何将缺少的依赖项添加到仅运行一次的 useEffect 挂钩?
- sql - 在一组日期之间查找季度结束日期 - Oracle SQL
- bootstrap-4 - 行中的引导图像对齐
- google-pay - 在没有 UI 的情况下生成 Google Pay 令牌
- android - 在android中的方向更改期间无法恢复表行
- sql - ORacle KEEP DENSE_RANK FIRST 的 Postgres 转换
- c# - 直接部署到 SQL Server 的集成服务
- html - 尝试在每个 50/50 100%Width 旁边创建带有图像和文本框的可堆叠容器?