【问题标题】:RxJS inside React Functional ComponentReact 功能组件中的 RxJS
【发布时间】:2020-09-09 13:54:29
【问题描述】:

这个问题的大部分是我试图创建反应组件,每个组件都有一个基于组件道具的可观察对象。我有几个位置,每个位置都有环境读数,我想独立生成 D3 图,以便使用 RxJS 来管理传入的数据。

我在这里有这个概念的工作版本:

https://www.lloydrichardsdesign.com/experiment/021

我遇到的问题是这个例子,我在组件外部硬编码了可观察的 firestore。但在我的下一个版本中,我想制作一个组件,它可以在加载时将 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 中,但随后 observable 从未收集到任何信息。

像这样:

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();
  }, []);

我现在有点茫然,不知道该怎么办。如果有人有任何想法或解决方案,将不胜感激!

【问题讨论】:

    标签: javascript reactjs google-cloud-firestore rxjs


    【解决方案1】:

    保持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 的错误并完成事件。

    【讨论】:

    猜你喜欢
    • 2021-08-06
    • 2020-12-28
    • 1970-01-01
    • 2020-05-30
    • 2020-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多