ReactJS Hooks 依赖一个异步操作

ReactJS Hooks dependency an async operation

所以我有一个挂载的钩子,它从 indexedDB 读取数据并将该数据存储在其内部状态

我遇到的问题是 indexedDB 数据从另一个组件 (added/removed) 更改,我需要在此挂钩中对这些更改做出反应。我不是 100% 熟悉钩子以及如何完成它,但首先想到的是将来自 indexedDB 的值作为钩子依赖项。

但是,从 indexedDB 读取数据是一个异步操作,挂钩依赖项将是一个 .. promise。

基本上,流程如下:

  1. 组件 1 像这样调用挂钩:
  const eventItems = useEventListItems({
    sortBy,
    sortGroupedBy,
    eventTimestamp,
    events,
    assets,
    touchedEventIds,
    unsyncedEvents, // <--- this is the one that we need
    order,
  });
  1. useEventListItems 挂钩在装载时从索引数据库中读取数据,将其存储在其内部状态中,returns 它:
  const { readUnsyncedEvents } = useDebriefStore();
  const [unsyncedEvents, setUnsyncedEvents] = useState<number[]>([]);
  useEffectAsync(async () => {
    const storedUnsyncedEventIds = await readUnsyncedEvents<number[]>();
    if (storedUnsyncedEventIds?.data) {
      setUnsyncedEvents(storedUnsyncedEventIds.data);
    }
  }, [setUnsyncedEvents]);

其中 readUnsyncedEvents 是:

export const readUnsyncedEvents = <T>(type: Type): Promise<DebriefStoreEntry<T>> =>
  debriefStore
    .get(type)
    .then((entry) => entry && { data: entry.data, timestamp: entry.timestamp });
  1. indexedDB 的 unsyncedEvents 然后从另一个组件更改。

  2. 现在应该发生的是,useEventListItems挂钩应该监听IDB中的变化并更新其内部状态的unsyncedEvents ,将它们传递给使用此挂钩的组件。我将如何实现这一目标?

我的第一个想法是在 useEventListItems 挂钩中有这样的东西:

useEffect(() => {
  setUnsyncedEvents(..newValueFromIdb);
}, [ await readUnsyncedEvents()]);

但这行不通,因为这是一个承诺。无论如何,我可以拥有一个异步操作返回的值作为钩子依赖吗?

您可以使用 Context API 从 IDB 重新获取数据。

这里的想法是创建一个带有计数器变量的上下文,该变量将在每次 IDB 更新操作后更新。 useEventListItems 挂钩将从上下文中读取该计数器变量并触发 useEffect 挂钩。

export const IDBContext = React.createContext({
  readFromIDB: null,
  setReadFromIDB: () => {}
});

export const IDBContextProvider = ({ children }) => {
  const [readFromIDB, setReadFromIDB] = useState(0);
  return (
    <IDBContext.Provider value={{ readFromIDB, setReadFromIDB }}>
      {children}
    </IDBContext.Provider>
  );
};  

这就是您的 useEventListItems 的样子。

const { readUnsyncedEvents } = useDebriefStore();
const [unsyncedEvents, setUnsyncedEvents] = useState<number[]>([]);

const {readFromIDB} = useContext(IDBContext); // this variable will be updated after each IDB update.

useEffectAsync(async () => {
  const storedUnsyncedEventIds = await readUnsyncedEvents<number[]>();
  if (storedUnsyncedEventIds?.data) {
    setUnsyncedEvents(storedUnsyncedEventIds.data);
  }
}, [readFromIDB,setUnsyncedEvents]); // added that to dependency array to trigger the hook on value change.

这里是组件:

const IDBUpdateComponent = ()=>{
const {readFromIDB,setReadFromIDB} = useContext(IDBContext);
  const updateIDB = ()=>{
    someIDBUpdateOpetation().then(res=>{
      setReadFromIDB(readFromIDB+1) // update the context after IDB update is successful.
    }).catch(e=>{})
  }

  return(
    <div>IDBUpdateComponent</div>
  );
}

const IDBConsumerComponent = ()=>{
  return (
    <div>IDBConsumerComponent</div>
  )
}

只需确保两个组件都包含在上下文中,以便它们可以访问值。

const App = ()=>{
  return(
    <div>
      <IDBContextProvider>
        <IDBUpdateComponent />
        <IDBConsumerComponent />
      </IDBContextProvider>
    </div>
  )
}