react-relay
Version:
A framework for building GraphQL-driven React applications.
241 lines (240 loc) • 13.7 kB
JavaScript
'use strict';
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var ProfilerContext = require('./ProfilerContext');
var _require = require('./QueryResource'),
getQueryResourceForEnvironment = _require.getQueryResourceForEnvironment;
var readFragmentInternal = require('./readFragmentInternal');
var useFragmentInternal = require('./useFragmentInternal');
var useIsMountedRef = require('./useIsMountedRef');
var useQueryLoader = require('./useQueryLoader');
var useRelayEnvironment = require('./useRelayEnvironment');
var invariant = require('invariant');
var _require2 = require('react'),
useCallback = _require2.useCallback,
useContext = _require2.useContext,
useReducer = _require2.useReducer;
var _require3 = require('relay-runtime'),
fetchQuery = _require3.__internal.fetchQuery,
createOperationDescriptor = _require3.createOperationDescriptor,
getFragmentIdentifier = _require3.getFragmentIdentifier,
getRefetchMetadata = _require3.getRefetchMetadata,
getSelector = _require3.getSelector,
getValueAtPath = _require3.getValueAtPath;
var warning = require("fbjs/lib/warning");
function reducer(state, action) {
switch (action.type) {
case 'refetch':
{
var _action$refetchEnviro;
return (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, state), {}, {
fetchPolicy: action.fetchPolicy,
mirroredEnvironment: (_action$refetchEnviro = action.refetchEnvironment) !== null && _action$refetchEnviro !== void 0 ? _action$refetchEnviro : state.mirroredEnvironment,
onComplete: action.onComplete,
refetchEnvironment: action.refetchEnvironment,
refetchQuery: action.refetchQuery,
renderPolicy: action.renderPolicy
});
}
case 'reset':
{
return {
fetchPolicy: undefined,
mirroredEnvironment: action.environment,
mirroredFragmentIdentifier: action.fragmentIdentifier,
onComplete: undefined,
refetchQuery: null,
renderPolicy: undefined
};
}
default:
{
action.type;
throw new Error('useRefetchableFragmentNode: Unexpected action type');
}
}
}
function useRefetchableFragmentNode(fragmentNode, parentFragmentRef, componentDisplayName) {
var parentEnvironment = useRelayEnvironment();
var _getRefetchMetadata = getRefetchMetadata(fragmentNode, componentDisplayName),
refetchableRequest = _getRefetchMetadata.refetchableRequest,
fragmentRefPathInResponse = _getRefetchMetadata.fragmentRefPathInResponse,
identifierInfo = _getRefetchMetadata.identifierInfo;
var fragmentIdentifier = getFragmentIdentifier(fragmentNode, parentFragmentRef);
var _useReducer = useReducer(reducer, {
fetchPolicy: undefined,
mirroredEnvironment: parentEnvironment,
mirroredFragmentIdentifier: fragmentIdentifier,
onComplete: undefined,
refetchEnvironment: null,
refetchQuery: null,
renderPolicy: undefined
}),
refetchState = _useReducer[0],
dispatch = _useReducer[1];
var fetchPolicy = refetchState.fetchPolicy,
mirroredEnvironment = refetchState.mirroredEnvironment,
mirroredFragmentIdentifier = refetchState.mirroredFragmentIdentifier,
onComplete = refetchState.onComplete,
refetchEnvironment = refetchState.refetchEnvironment,
refetchQuery = refetchState.refetchQuery,
renderPolicy = refetchState.renderPolicy;
var environment = refetchEnvironment !== null && refetchEnvironment !== void 0 ? refetchEnvironment : parentEnvironment;
var QueryResource = getQueryResourceForEnvironment(environment);
var profilerContext = useContext(ProfilerContext);
var shouldReset = environment !== mirroredEnvironment || fragmentIdentifier !== mirroredFragmentIdentifier;
var _useQueryLoader = useQueryLoader(refetchableRequest),
queryRef = _useQueryLoader[0],
loadQuery = _useQueryLoader[1],
disposeQuery = _useQueryLoader[2];
var fragmentRef = parentFragmentRef;
if (shouldReset) {
dispatch({
type: 'reset',
environment: environment,
fragmentIdentifier: fragmentIdentifier
});
disposeQuery();
} else if (refetchQuery != null && queryRef != null) {
var debugPreviousIDAndTypename;
if (process.env.NODE_ENV !== "production") {
debugPreviousIDAndTypename = debugFunctions.getInitialIDAndType(refetchQuery.request.variables, fragmentRefPathInResponse, identifierInfo === null || identifierInfo === void 0 ? void 0 : identifierInfo.identifierQueryVariableName, environment);
}
var handleQueryCompleted = function handleQueryCompleted(maybeError) {
onComplete && onComplete(maybeError !== null && maybeError !== void 0 ? maybeError : null);
};
var fetchObservable = queryRef.source != null ? queryRef.source : fetchQuery(environment, refetchQuery);
var queryResult = profilerContext.wrapPrepareQueryResource(function () {
return QueryResource.prepare(refetchQuery, fetchObservable, fetchPolicy, renderPolicy, {
error: handleQueryCompleted,
complete: function complete() {
if (process.env.NODE_ENV !== "production") {
debugFunctions.checkSameTypeAfterRefetch(debugPreviousIDAndTypename, environment, fragmentNode, componentDisplayName);
}
handleQueryCompleted();
}
}, queryRef.fetchKey, profilerContext);
});
var queryData = readFragmentInternal(environment, queryResult.fragmentNode, queryResult.fragmentRef, componentDisplayName).data;
!(queryData != null) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Relay: Expected to be able to read refetch query response. ' + "If you're seeing this, this is likely a bug in Relay.") : invariant(false) : void 0;
var refetchedFragmentRef = getValueAtPath(queryData, fragmentRefPathInResponse);
fragmentRef = refetchedFragmentRef;
if (process.env.NODE_ENV !== "production") {
debugFunctions.checkSameIDAfterRefetch(debugPreviousIDAndTypename, fragmentRef, fragmentNode, componentDisplayName);
}
}
var fragmentData = useFragmentInternal(fragmentNode, fragmentRef, componentDisplayName);
var refetch = useRefetchFunction(componentDisplayName, dispatch, disposeQuery, fragmentData, fragmentIdentifier, fragmentNode, fragmentRefPathInResponse, identifierInfo, loadQuery, parentFragmentRef, refetchableRequest);
return {
fragmentData: fragmentData,
fragmentRef: fragmentRef,
refetch: refetch
};
}
function useRefetchFunction(componentDisplayName, dispatch, disposeQuery, fragmentData, fragmentIdentifier, fragmentNode, fragmentRefPathInResponse, identifierInfo, loadQuery, parentFragmentRef, refetchableRequest) {
var isMountedRef = useIsMountedRef();
var identifierValue = (identifierInfo === null || identifierInfo === void 0 ? void 0 : identifierInfo.identifierField) != null && fragmentData != null && typeof fragmentData === 'object' ? fragmentData[identifierInfo.identifierField] : null;
return useCallback(function (providedRefetchVariables, options) {
if (isMountedRef.current !== true) {
process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Unexpected call to `refetch` on unmounted component for fragment ' + '`%s` in `%s`. It looks like some instances of your component are ' + 'still trying to fetch data but they already unmounted. ' + 'Please make sure you clear all timers, intervals, ' + 'async calls, etc that may trigger a fetch.', fragmentNode.name, componentDisplayName) : void 0;
return {
dispose: function dispose() {}
};
}
if (parentFragmentRef == null) {
process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Unexpected call to `refetch` while using a null fragment ref ' + 'for fragment `%s` in `%s`. When calling `refetch`, we expect ' + "initial fragment data to be non-null. Please make sure you're " + 'passing a valid fragment ref to `%s` before calling ' + '`refetch`, or make sure you pass all required variables to `refetch`.', fragmentNode.name, componentDisplayName, componentDisplayName) : void 0;
}
var refetchEnvironment = options === null || options === void 0 ? void 0 : options.__environment;
var fetchPolicy = options === null || options === void 0 ? void 0 : options.fetchPolicy;
var renderPolicy = options === null || options === void 0 ? void 0 : options.UNSTABLE_renderPolicy;
var onComplete = options === null || options === void 0 ? void 0 : options.onComplete;
var fragmentSelector = getSelector(fragmentNode, parentFragmentRef);
var parentVariables;
var fragmentVariables;
if (fragmentSelector == null) {
parentVariables = {};
fragmentVariables = {};
} else if (fragmentSelector.kind === 'PluralReaderSelector') {
var _fragmentSelector$sel, _fragmentSelector$sel2, _fragmentSelector$sel3, _fragmentSelector$sel4;
parentVariables = (_fragmentSelector$sel = (_fragmentSelector$sel2 = fragmentSelector.selectors[0]) === null || _fragmentSelector$sel2 === void 0 ? void 0 : _fragmentSelector$sel2.owner.variables) !== null && _fragmentSelector$sel !== void 0 ? _fragmentSelector$sel : {};
fragmentVariables = (_fragmentSelector$sel3 = (_fragmentSelector$sel4 = fragmentSelector.selectors[0]) === null || _fragmentSelector$sel4 === void 0 ? void 0 : _fragmentSelector$sel4.variables) !== null && _fragmentSelector$sel3 !== void 0 ? _fragmentSelector$sel3 : {};
} else {
parentVariables = fragmentSelector.owner.variables;
fragmentVariables = fragmentSelector.variables;
}
var refetchVariables = (0, _objectSpread2["default"])((0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, parentVariables), fragmentVariables), providedRefetchVariables);
if (identifierInfo != null && !providedRefetchVariables.hasOwnProperty(identifierInfo.identifierQueryVariableName)) {
if (typeof identifierValue !== 'string') {
process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Expected result to have a string ' + '`%s` in order to refetch, got `%s`.', identifierInfo.identifierField, identifierValue) : void 0;
}
refetchVariables[identifierInfo.identifierQueryVariableName] = identifierValue;
}
var refetchQuery = createOperationDescriptor(refetchableRequest, refetchVariables, {
force: true
});
loadQuery(refetchQuery.request.variables, {
fetchPolicy: fetchPolicy,
__environment: refetchEnvironment,
__nameForWarning: 'refetch'
});
dispatch({
type: 'refetch',
fetchPolicy: fetchPolicy,
onComplete: onComplete,
refetchEnvironment: refetchEnvironment,
refetchQuery: refetchQuery,
renderPolicy: renderPolicy
});
return {
dispose: disposeQuery
};
}, [fragmentIdentifier, dispatch, disposeQuery, identifierValue, loadQuery]);
}
var debugFunctions;
if (process.env.NODE_ENV !== "production") {
debugFunctions = {
getInitialIDAndType: function getInitialIDAndType(memoRefetchVariables, fragmentRefPathInResponse, identifierQueryVariableName, environment) {
var _require4 = require('relay-runtime'),
Record = _require4.Record;
var id = memoRefetchVariables === null || memoRefetchVariables === void 0 ? void 0 : memoRefetchVariables[identifierQueryVariableName !== null && identifierQueryVariableName !== void 0 ? identifierQueryVariableName : 'id'];
if (fragmentRefPathInResponse.length !== 1 || fragmentRefPathInResponse[0] !== 'node' || id == null) {
return null;
}
var recordSource = environment.getStore().getSource();
var record = recordSource.get(id);
var typename = record == null ? null : Record.getType(record);
if (typename == null) {
return null;
}
return {
id: id,
typename: typename
};
},
checkSameTypeAfterRefetch: function checkSameTypeAfterRefetch(previousIDAndType, environment, fragmentNode, componentDisplayName) {
var _require5 = require('relay-runtime'),
Record = _require5.Record;
if (!previousIDAndType) {
return;
}
var recordSource = environment.getStore().getSource();
var record = recordSource.get(previousIDAndType.id);
var typename = record && Record.getType(record);
if (typename !== previousIDAndType.typename) {
process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Call to `refetch` returned data with a different ' + '__typename: was `%s`, now `%s`, on `%s` in `%s`. ' + 'Please make sure the server correctly implements' + 'unique id requirement.', previousIDAndType.typename, typename, fragmentNode.name, componentDisplayName) : void 0;
}
},
checkSameIDAfterRefetch: function checkSameIDAfterRefetch(previousIDAndTypename, refetchedFragmentRef, fragmentNode, componentDisplayName) {
if (previousIDAndTypename == null) {
return;
}
var _require6 = require('relay-runtime'),
ID_KEY = _require6.ID_KEY;
var resultID = refetchedFragmentRef[ID_KEY];
if (resultID != null && resultID !== previousIDAndTypename.id) {
process.env.NODE_ENV !== "production" ? warning(false, 'Relay: Call to `refetch` returned a different id, expected ' + '`%s`, got `%s`, on `%s` in `%s`. ' + 'Please make sure the server correctly implements ' + 'unique id requirement.', resultID, previousIDAndTypename.id, fragmentNode.name, componentDisplayName) : void 0;
}
}
};
}
module.exports = useRefetchableFragmentNode;