[英]RxJS inside React Functional Component
这个问题的大部分是我试图创建反应组件,每个组件都有一个基于组件道具的可观察对象。 我有几个位置,每个位置都有环境读数,我想独立生成 D3 图以使用 RxJS 来管理传入的数据。
我在这里有一个这个概念的工作版本:
https://www.lloydrichardsdesign.com/experiment/021
我遇到的问题是在这个例子中,我在组件外部对 firestore observable 进行了硬编码。 但是在我的下一个版本中,我想制作一个组件,该组件可以在加载时将 locationId 提供给 observable,然后每个组件管理自己的状态。
这看起来像:
import { Observable } from "rxjs"
import { Dispatch, SetStateAction, useEffect, useState } from "react";
const useObservable = (observable: Observable<any>, setter: Dispatch<SetStateAction<any>>) => {
useEffect(()=>{
let subscription = observable.subscribe(result => {
setter(result);
});
return ()=> subscription.unsubscribe()
},[observable, setter])
}
const LocationItem: React.FC<LocationProps> = ({ location }) => {
const [readings, setReadings] = useState<Array<Reading>>([]);
const dataObservable = collectionData(
db
.collection('mimirReading')
.where('locationId', '==', location.id)
.orderBy('timestamp', 'desc')
.limit(48)
);
useObservable(dataObservable, setReadings);
return(
<ol>
{readings.map(r=><li>{r.timestamp}</li>)}
</ol>
)
}
问题是,这导致 useObservable 被一遍又一遍地调用,从不返回任何数据。 我最终得到一个空的读数状态,我的控制台发疯了。
我想,我必须在组件第一次挂载时创建 dataObservable,所以在 useEffect 中,但是我会得到与在其内部调用 useEffect 相关的错误。 最后,我尝试在第一次创建组件时将订阅拉出并放入 useEffect,但随后可观察对象从未收集任何信息。
像这样:
useEffect(() => {
const dataObservable = collectionData(
db
.collection('mimirReading')
.where('locationId', '==', location.id)
.orderBy('timestamp', 'desc')
.limit(48)
).subscribe((reads) => {
console.log(reads);
setReadings(reads as Array<Reading>);
});
console.log(dataObservable);
return () => dataObservable.unsubscribe();
}, []);
我现在有点不知所措,不知道该怎么办。 如果有人有任何想法或解决方案,将不胜感激!
保持useObservable
钩子隔离,并创建一个可观察值(记忆到位置 id)以传递给它:
const useObservable = (observable, setter) => {
useEffect(() => {
let subscription = observable.subscribe(result => {
setter(result);
});
return () => subscription.unsubscribe()
},
[observable, setter]
);
};
const LocationItem = ({ location }) => {
const [readings, setReadings] = useState([]);
const dataObservable = useMemo(() => {
return collectionData(
db
.collection('mimirReading')
.where('locationId', '==', location.id)
.orderBy('timestamp', 'desc')
.limit(48)
);
}, [location.id]);
useObservable(dataObservable, setReadings);
return (
<ol>
{readings.map((r) => (
<li>{r.timestamp}</li>
))}
</ol>
);
};
或者,我还建议将状态的所有权更改为useObservable
:
const useObservable = (observable) => {
const [value, setValue] = useState();
useEffect(() => {
let subscription = observable.subscribe((result) => {
setValue(result);
});
return () => subscription.unsubscribe();
}, [observable]);
return value;
};
这样你就不需要外部状态设置器,它总是在钩子内处理。 您还可以在useObservable
使用setState
来捕获 observable 的错误和完成事件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.