react-relay
Version:
A framework for building GraphQL-driven React applications.
286 lines (285 loc) • 10.8 kB
JavaScript
'use strict';
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"];
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var ReactRelayContext = require('./ReactRelayContext');
var ReactRelayQueryFetcher = require('./ReactRelayQueryFetcher');
var ReactRelayQueryRendererContext = require('./ReactRelayQueryRendererContext');
var areEqual = require("fbjs/lib/areEqual");
var React = require('react');
var _require = require('relay-runtime'),
createOperationDescriptor = _require.createOperationDescriptor,
deepFreeze = _require.deepFreeze,
getRequest = _require.getRequest;
var requestCache = {};
var queryRendererContext = {
rootIsQueryRenderer: true
};
var ReactRelayQueryRenderer = /*#__PURE__*/function (_React$Component) {
(0, _inheritsLoose2["default"])(ReactRelayQueryRenderer, _React$Component);
function ReactRelayQueryRenderer(props) {
var _this;
_this = _React$Component.call(this, props) || this;
(0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_handleDataChange", function (params) {
var error = params.error == null ? null : params.error;
var snapshot = params.snapshot == null ? null : params.snapshot;
_this.setState(function (prevState) {
var prevRequestCacheKey = prevState.requestCacheKey;
if (prevRequestCacheKey) {
delete requestCache[prevRequestCacheKey];
}
if (snapshot === prevState.snapshot && error === prevState.error) {
return null;
}
return {
renderProps: getRenderProps(error, snapshot, prevState.queryFetcher, prevState.retryCallbacks),
snapshot: snapshot,
requestCacheKey: null
};
});
});
var retryCallbacks = {
handleDataChange: null,
handleRetryAfterError: null
};
var queryFetcher;
var requestCacheKey;
if (props.query) {
var query = props.query;
var request = getRequest(query);
requestCacheKey = getRequestCacheKey(request.params, props.variables);
queryFetcher = requestCache[requestCacheKey] ? requestCache[requestCacheKey].queryFetcher : new ReactRelayQueryFetcher();
} else {
queryFetcher = new ReactRelayQueryFetcher();
}
_this._maybeHiddenOrFastRefresh = false;
_this.state = (0, _objectSpread2["default"])({
prevPropsEnvironment: props.environment,
prevPropsVariables: props.variables,
prevQuery: props.query,
queryFetcher: queryFetcher,
retryCallbacks: retryCallbacks
}, fetchQueryAndComputeStateFromProps(props, queryFetcher, retryCallbacks, requestCacheKey));
return _this;
}
ReactRelayQueryRenderer.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
if (prevState.prevQuery !== nextProps.query || prevState.prevPropsEnvironment !== nextProps.environment || !areEqual(prevState.prevPropsVariables, nextProps.variables)) {
return resetQueryStateForUpdate(nextProps, prevState);
}
return null;
};
var _proto = ReactRelayQueryRenderer.prototype;
_proto.componentDidMount = function componentDidMount() {
var _this2 = this;
if (this._maybeHiddenOrFastRefresh === true) {
this._maybeHiddenOrFastRefresh = false;
this.setState(function (prevState) {
var newState = resetQueryStateForUpdate(_this2.props, prevState);
var requestCacheKey = newState.requestCacheKey,
queryFetcher = newState.queryFetcher;
if (requestCacheKey != null && requestCache[requestCacheKey] != null) {
queryFetcher.setOnDataChange(_this2._handleDataChange);
}
return newState;
});
return;
}
var _this$state = this.state,
retryCallbacks = _this$state.retryCallbacks,
queryFetcher = _this$state.queryFetcher,
requestCacheKey = _this$state.requestCacheKey;
if (requestCacheKey) {
delete requestCache[requestCacheKey];
}
retryCallbacks.handleDataChange = this._handleDataChange;
retryCallbacks.handleRetryAfterError = function (error) {
return _this2.setState(function (prevState) {
var prevRequestCacheKey = prevState.requestCacheKey;
if (prevRequestCacheKey) {
delete requestCache[prevRequestCacheKey];
}
return {
renderProps: getLoadingRenderProps(),
requestCacheKey: null
};
});
};
if (this.props.query) {
queryFetcher.setOnDataChange(this._handleDataChange);
}
};
_proto.componentDidUpdate = function componentDidUpdate(_prevProps, prevState) {
var _this$state2 = this.state,
queryFetcher = _this$state2.queryFetcher,
requestCacheKey = _this$state2.requestCacheKey;
if (requestCacheKey) {
delete requestCache[requestCacheKey];
delete this.state.requestCacheKey;
}
if (this.props.query && queryFetcher !== prevState.queryFetcher) {
queryFetcher.setOnDataChange(this._handleDataChange);
}
};
_proto.componentWillUnmount = function componentWillUnmount() {
this.state.queryFetcher.dispose();
this._maybeHiddenOrFastRefresh = true;
};
_proto.shouldComponentUpdate = function shouldComponentUpdate(nextProps, nextState) {
return nextProps.render !== this.props.render || nextState.renderProps !== this.state.renderProps;
};
_proto.render = function render() {
var _this$state3 = this.state,
renderProps = _this$state3.renderProps,
relayContext = _this$state3.relayContext;
if (process.env.NODE_ENV !== "production") {
deepFreeze(renderProps);
}
return /*#__PURE__*/React.createElement(ReactRelayContext.Provider, {
value: relayContext
}, /*#__PURE__*/React.createElement(ReactRelayQueryRendererContext.Provider, {
value: queryRendererContext
}, this.props.render(renderProps)));
};
return ReactRelayQueryRenderer;
}(React.Component);
function getLoadingRenderProps() {
return {
error: null,
props: null,
retry: null
};
}
function getEmptyRenderProps() {
return {
error: null,
props: {},
retry: null
};
}
function getRenderProps(error, snapshot, queryFetcher, retryCallbacks) {
return {
error: error ? error : null,
props: snapshot ? snapshot.data : null,
retry: function retry(cacheConfigOverride) {
var syncSnapshot = queryFetcher.retry(cacheConfigOverride);
if (syncSnapshot && typeof retryCallbacks.handleDataChange === 'function') {
retryCallbacks.handleDataChange({
snapshot: syncSnapshot
});
} else if (error && typeof retryCallbacks.handleRetryAfterError === 'function') {
retryCallbacks.handleRetryAfterError(error);
}
}
};
}
function getRequestCacheKey(request, variables) {
return JSON.stringify({
id: request.cacheID ? request.cacheID : request.id,
variables: variables
});
}
function resetQueryStateForUpdate(props, prevState) {
var query = props.query;
var prevSelectionReferences = prevState.queryFetcher.getSelectionReferences();
prevState.queryFetcher.disposeRequest();
var queryFetcher;
if (query) {
var request = getRequest(query);
var requestCacheKey = getRequestCacheKey(request.params, props.variables);
queryFetcher = requestCache[requestCacheKey] ? requestCache[requestCacheKey].queryFetcher : new ReactRelayQueryFetcher(prevSelectionReferences);
} else {
queryFetcher = new ReactRelayQueryFetcher(prevSelectionReferences);
}
return (0, _objectSpread2["default"])({
prevQuery: props.query,
prevPropsEnvironment: props.environment,
prevPropsVariables: props.variables,
queryFetcher: queryFetcher
}, fetchQueryAndComputeStateFromProps(props, queryFetcher, prevState.retryCallbacks));
}
function fetchQueryAndComputeStateFromProps(props, queryFetcher, retryCallbacks, requestCacheKey) {
var environment = props.environment,
query = props.query,
variables = props.variables,
cacheConfig = props.cacheConfig;
var genericEnvironment = environment;
if (query) {
var request = getRequest(query);
var operation = createOperationDescriptor(request, variables, cacheConfig);
var relayContext = {
environment: genericEnvironment
};
if (typeof requestCacheKey === 'string' && requestCache[requestCacheKey]) {
var snapshot = requestCache[requestCacheKey].snapshot;
if (snapshot) {
return {
error: null,
relayContext: relayContext,
renderProps: getRenderProps(null, snapshot, queryFetcher, retryCallbacks),
snapshot: snapshot,
requestCacheKey: requestCacheKey
};
} else {
return {
error: null,
relayContext: relayContext,
renderProps: getLoadingRenderProps(),
snapshot: null,
requestCacheKey: requestCacheKey
};
}
}
try {
var storeSnapshot = queryFetcher.lookupInStore(genericEnvironment, operation, props.fetchPolicy);
var querySnapshot = queryFetcher.fetch({
environment: genericEnvironment,
onDataChange: null,
operation: operation
});
var _snapshot = querySnapshot || storeSnapshot;
requestCacheKey = requestCacheKey || getRequestCacheKey(request.params, props.variables);
requestCache[requestCacheKey] = {
queryFetcher: queryFetcher,
snapshot: _snapshot
};
if (!_snapshot) {
return {
error: null,
relayContext: relayContext,
renderProps: getLoadingRenderProps(),
snapshot: null,
requestCacheKey: requestCacheKey
};
}
return {
error: null,
relayContext: relayContext,
renderProps: getRenderProps(null, _snapshot, queryFetcher, retryCallbacks),
snapshot: _snapshot,
requestCacheKey: requestCacheKey
};
} catch (error) {
return {
error: error,
relayContext: relayContext,
renderProps: getRenderProps(error, null, queryFetcher, retryCallbacks),
snapshot: null,
requestCacheKey: requestCacheKey
};
}
} else {
queryFetcher.dispose();
var _relayContext = {
environment: genericEnvironment
};
return {
error: null,
relayContext: _relayContext,
renderProps: getEmptyRenderProps(),
requestCacheKey: null
};
}
}
module.exports = ReactRelayQueryRenderer;