graphql-hooks
Version:
242 lines (194 loc) • 7.08 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var GraphQLClient = require('./GraphQLClient-719063e6.js');
var React = _interopDefault(require('react'));
var ClientContext = React.createContext();
ClientContext.displayName = 'ClientContext';
var actionTypes = {
RESET_STATE: 'RESET_STATE',
LOADING: 'LOADING',
CACHE_HIT: 'CACHE_HIT',
REQUEST_RESULT: 'REQUEST_RESULT'
};
function reducer(state, action) {
switch (action.type) {
case actionTypes.RESET_STATE:
return action.initialState;
case actionTypes.LOADING:
if (state.loading) {
return state; // saves a render cycle as state is the same
}
return GraphQLClient._objectSpread({}, state, {
loading: true
});
case actionTypes.CACHE_HIT:
if (state.cacheHit) {
// we can be sure this is the same cacheKey hit
// because we dispatch RESET_STATE if it changes
return state;
}
return GraphQLClient._objectSpread({}, action.result, {
cacheHit: true,
loading: false
});
case actionTypes.REQUEST_RESULT:
return GraphQLClient._objectSpread({}, action.result, {
cacheHit: false,
loading: false
});
default:
return state;
}
}
/*
options include:
opts.variables: Object
opts.operationName: String
opts.fetchOptionsOverrides: Object
opts.skipCache: Boolean
*/
function useClientRequest(query, initialOpts) {
if (initialOpts === void 0) {
initialOpts = {};
}
var client = React.useContext(ClientContext);
var isMounted = React.useRef(true);
var activeCacheKey = React.useRef(null);
var operation = {
query: query,
variables: initialOpts.variables,
operationName: initialOpts.operationName
};
var cacheKey = client.getCacheKey(operation, initialOpts);
var isDeferred = initialOpts.isMutation || initialOpts.isManual;
var initialCacheHit = initialOpts.skipCache || !client.cache ? null : client.cache.get(cacheKey);
var initialState = GraphQLClient._objectSpread({}, initialCacheHit, {
cacheHit: !!initialCacheHit,
loading: isDeferred ? false : !initialCacheHit
});
var _React$useReducer = React.useReducer(reducer, initialState),
state = _React$useReducer[0],
dispatch = _React$useReducer[1]; // NOTE: state from useReducer is only initialState on the first render
// in subsequent renders the operation could have changed
// if so the state would be invalid, this effect ensures we reset it back
var stringifiedCacheKey = JSON.stringify(cacheKey);
React.useEffect(function () {
if (!initialOpts.updateData) {
// if using updateData we can assume that the consumer cares about the previous data
dispatch({
type: actionTypes.RESET_STATE,
initialState: initialState
});
}
}, [stringifiedCacheKey]); // eslint-disable-line react-hooks/exhaustive-deps
React.useEffect(function () {
isMounted.current = true;
return function () {
isMounted.current = false;
};
}, []); // arguments to fetchData override the useClientRequest arguments
function fetchData(newOpts) {
if (!isMounted.current) return Promise.resolve();
var revisedOpts = GraphQLClient._objectSpread({}, initialOpts, newOpts);
var revisedOperation = GraphQLClient._objectSpread({}, operation, {
variables: revisedOpts.variables,
operationName: revisedOpts.operationName
});
var revisedCacheKey = client.getCacheKey(revisedOperation, revisedOpts); // NOTE: There is a possibility of a race condition whereby
// the second query could finish before the first one, dispatching an old result
// see https://github.com/nearform/graphql-hooks/issues/150
activeCacheKey.current = revisedCacheKey;
var cacheHit = revisedOpts.skipCache || !client.cache ? null : client.cache.get(revisedCacheKey);
if (cacheHit) {
dispatch({
type: actionTypes.CACHE_HIT,
result: cacheHit
});
return Promise.resolve(cacheHit);
}
dispatch({
type: actionTypes.LOADING
});
return client.request(revisedOperation, revisedOpts).then(function (result) {
if (state.data && result.data && revisedOpts.updateData) {
if (typeof revisedOpts.updateData !== 'function') {
throw new Error('options.updateData must be a function');
}
result.data = revisedOpts.updateData(state.data, result.data);
}
if (revisedOpts.useCache && client.cache) {
client.cache.set(revisedCacheKey, result);
}
if (isMounted.current && revisedCacheKey === activeCacheKey.current) {
dispatch({
type: actionTypes.REQUEST_RESULT,
result: result
});
}
return result;
});
}
return [fetchData, state];
}
var defaultOpts = {
useCache: true
};
function useQuery(query, opts) {
if (opts === void 0) {
opts = {};
}
var allOpts = GraphQLClient._objectSpread({}, defaultOpts, opts);
var client = React.useContext(ClientContext);
var _React$useState = React.useState(false),
calledDuringSSR = _React$useState[0],
setCalledDuringSSR = _React$useState[1];
var _useClientRequest = useClientRequest(query, allOpts),
queryReq = _useClientRequest[0],
state = _useClientRequest[1];
if (client.ssrMode && opts.ssr !== false && !calledDuringSSR) {
// result may already be in the cache from previous SSR iterations
if (!state.data && !state.error) {
var p = queryReq();
client.ssrPromises.push(p);
}
setCalledDuringSSR(true);
}
var stringifiedAllOpts = JSON.stringify(allOpts);
React.useEffect(function () {
queryReq();
}, [query, stringifiedAllOpts]); // eslint-disable-line react-hooks/exhaustive-deps
return GraphQLClient._objectSpread({}, state, {
refetch: function refetch(options) {
if (options === void 0) {
options = {};
}
return queryReq(GraphQLClient._objectSpread({
skipCache: true,
// don't call the updateData that has been passed into useQuery here
// reset to the default behaviour of returning the raw query result
// this can be overridden in refetch options
updateData: function updateData(_, data) {
return data;
}
}, options));
}
});
}
var useManualQuery = function useManualQuery(query, options) {
return useClientRequest(query, GraphQLClient._objectSpread({
useCache: true,
isManual: true
}, options));
};
var useMutation = function useMutation(query, options) {
return useClientRequest(query, GraphQLClient._objectSpread({
isMutation: true
}, options));
};
exports.GraphQLClient = GraphQLClient.GraphQLClient;
exports.ClientContext = ClientContext;
exports.useClientRequest = useClientRequest;
exports.useManualQuery = useManualQuery;
exports.useMutation = useMutation;
exports.useQuery = useQuery;