@graffy/react
Version:
This built-in module provides an idiomatic React API to a Graffy store.
95 lines (94 loc) • 2.58 kB
JavaScript
import PropTypes from "prop-types";
import React from "react";
import isEqual from "lodash/isEqual.js";
const { createContext } = React;
const GraffyContext = createContext(null);
function GraffyProvider({ store, children }) {
return /* @__PURE__ */ React.createElement(GraffyContext.Provider, { value: store }, children);
}
GraffyProvider.propTypes = {
store: PropTypes.object.isRequired,
children: PropTypes.node
};
const { useRef, useState, useEffect, useContext: useContext$1 } = React;
const consumeSubscription = async (subscription, setState) => {
try {
for await (const data of subscription) {
if (subscription.closed) {
break;
}
setState((prevState) => ({
...prevState,
loading: false,
data,
error: null
}));
}
} catch (error) {
setState((prevState) => ({
...prevState,
loading: false,
data: null,
error
}));
}
};
const retrieveResult = async (promise, setState) => {
try {
const data = await promise;
setState((prevState) => ({
...prevState,
loading: false,
data,
error: null
}));
} catch (error) {
setState((prevState) => ({
...prevState,
loading: false,
data: null,
error
}));
}
};
function useQuery(query, { once = false, ...other } = {}) {
const store = useContext$1(GraffyContext);
const queryRef = useRef(null);
if (!store) throw Error("graffy_react.no_store_in_context");
const queryHasChanged = !isEqual(queryRef.current, query);
if (queryHasChanged) {
queryRef.current = query;
}
const fetchData = (options = other) => {
if (state.loading !== true) setState({ ...state, loading: true });
if (once) {
retrieveResult(store.read(query, options), setState);
} else {
const subscription = store.watch(query, options);
consumeSubscription(subscription, setState);
return () => {
subscription.closed = true;
subscription.return();
};
}
};
const refetch = fetchData.bind(null, { ...other, skipCache: true });
const [state, setState] = useState({ loading: true });
useEffect(fetchData, [queryRef.current, store]);
return once ? { ...state, refetch } : state;
}
function Query({ query, options, children }) {
const { data, loading, error } = useQuery(query, options);
return children({ data, loading, error });
}
const { useContext } = React;
function useStore() {
const store = useContext(GraffyContext);
return store;
}
export {
GraffyProvider,
Query,
useQuery,
useStore
};