问题描述
这个问题的大部分是我试图基于组件的道具创建每个具有可观察到的反应组件。我有几个位置,每个位置都有环境读数,我想独立生成D3图以使用RxJS来管理传入的数据。
我在这里有这个概念的有效版本:
https://www.lloydrichardsdesign.com/experiment/021
我遇到的问题与该示例有关,我已在组件外部对可观察到的firestore进行了硬编码。但是在下一个版本中,我想制作一个组件,该组件可以在加载时将locationId输入到可观察对象,然后每个组件管理自己的状态。
这看起来像:
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;
};
这样,您不需要外部状态设置器,它总是在挂钩中处理。您还可以在setState
中使用useObservable
来捕获可观察对象的错误并完成事件。