react-query
Version:
Hooks for managing, caching and syncing asynchronous and remote data in React
253 lines (214 loc) • 7.29 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.Mutation = void 0;
exports.getDefaultState = getDefaultState;
var _logger = require("./logger");
var _notifyManager = require("./notifyManager");
var _removable = require("./removable");
var _retryer = require("./retryer");
// CLASS
class Mutation extends _removable.Removable {
constructor(config) {
super();
this.options = { ...config.defaultOptions,
...config.options
};
this.mutationId = config.mutationId;
this.mutationCache = config.mutationCache;
this.logger = config.logger || _logger.defaultLogger;
this.observers = [];
this.state = config.state || getDefaultState();
this.meta = config.meta;
this.updateCacheTime(this.options.cacheTime);
this.scheduleGc();
}
setState(state) {
this.dispatch({
type: 'setState',
state
});
}
addObserver(observer) {
if (this.observers.indexOf(observer) === -1) {
this.observers.push(observer); // Stop the mutation from being garbage collected
this.clearGcTimeout();
this.mutationCache.notify({
type: 'observerAdded',
mutation: this,
observer
});
}
}
removeObserver(observer) {
this.observers = this.observers.filter(x => x !== observer);
this.scheduleGc();
this.mutationCache.notify({
type: 'observerRemoved',
mutation: this,
observer
});
}
optionalRemove() {
if (!this.observers.length) {
if (this.state.status === 'loading') {
this.scheduleGc();
} else {
this.mutationCache.remove(this);
}
}
}
continue() {
if (this.retryer) {
this.retryer.continue();
return this.retryer.promise;
}
return this.execute();
}
async execute() {
const executeMutation = () => {
var _this$options$retry;
this.retryer = (0, _retryer.createRetryer)({
fn: () => {
if (!this.options.mutationFn) {
return Promise.reject('No mutationFn found');
}
return this.options.mutationFn(this.state.variables);
},
onFail: () => {
this.dispatch({
type: 'failed'
});
},
onPause: () => {
this.dispatch({
type: 'pause'
});
},
onContinue: () => {
this.dispatch({
type: 'continue'
});
},
retry: (_this$options$retry = this.options.retry) != null ? _this$options$retry : 0,
retryDelay: this.options.retryDelay,
networkMode: this.options.networkMode
});
return this.retryer.promise;
};
const restored = this.state.status === 'loading';
try {
var _this$mutationCache$c3, _this$mutationCache$c4, _this$options$onSucce, _this$options2, _this$options$onSettl, _this$options3;
if (!restored) {
var _this$mutationCache$c, _this$mutationCache$c2, _this$options$onMutat, _this$options;
this.dispatch({
type: 'loading',
variables: this.options.variables
}); // Notify cache callback
(_this$mutationCache$c = (_this$mutationCache$c2 = this.mutationCache.config).onMutate) == null ? void 0 : _this$mutationCache$c.call(_this$mutationCache$c2, this.state.variables, this);
const context = await ((_this$options$onMutat = (_this$options = this.options).onMutate) == null ? void 0 : _this$options$onMutat.call(_this$options, this.state.variables));
if (context !== this.state.context) {
this.dispatch({
type: 'loading',
context,
variables: this.state.variables
});
}
}
const data = await executeMutation(); // Notify cache callback
(_this$mutationCache$c3 = (_this$mutationCache$c4 = this.mutationCache.config).onSuccess) == null ? void 0 : _this$mutationCache$c3.call(_this$mutationCache$c4, data, this.state.variables, this.state.context, this);
await ((_this$options$onSucce = (_this$options2 = this.options).onSuccess) == null ? void 0 : _this$options$onSucce.call(_this$options2, data, this.state.variables, this.state.context));
await ((_this$options$onSettl = (_this$options3 = this.options).onSettled) == null ? void 0 : _this$options$onSettl.call(_this$options3, data, null, this.state.variables, this.state.context));
this.dispatch({
type: 'success',
data
});
return data;
} catch (error) {
try {
var _this$mutationCache$c5, _this$mutationCache$c6, _this$options$onError, _this$options4, _this$options$onSettl2, _this$options5;
// Notify cache callback
(_this$mutationCache$c5 = (_this$mutationCache$c6 = this.mutationCache.config).onError) == null ? void 0 : _this$mutationCache$c5.call(_this$mutationCache$c6, error, this.state.variables, this.state.context, this);
if (process.env.NODE_ENV !== 'production') {
this.logger.error(error);
}
await ((_this$options$onError = (_this$options4 = this.options).onError) == null ? void 0 : _this$options$onError.call(_this$options4, error, this.state.variables, this.state.context));
await ((_this$options$onSettl2 = (_this$options5 = this.options).onSettled) == null ? void 0 : _this$options$onSettl2.call(_this$options5, undefined, error, this.state.variables, this.state.context));
throw error;
} finally {
this.dispatch({
type: 'error',
error: error
});
}
}
}
dispatch(action) {
const reducer = state => {
switch (action.type) {
case 'failed':
return { ...state,
failureCount: state.failureCount + 1
};
case 'pause':
return { ...state,
isPaused: true
};
case 'continue':
return { ...state,
isPaused: false
};
case 'loading':
return { ...state,
context: action.context,
data: undefined,
error: null,
isPaused: !(0, _retryer.canFetch)(this.options.networkMode),
status: 'loading',
variables: action.variables
};
case 'success':
return { ...state,
data: action.data,
error: null,
status: 'success',
isPaused: false
};
case 'error':
return { ...state,
data: undefined,
error: action.error,
failureCount: state.failureCount + 1,
isPaused: false,
status: 'error'
};
case 'setState':
return { ...state,
...action.state
};
}
};
this.state = reducer(this.state);
_notifyManager.notifyManager.batch(() => {
this.observers.forEach(observer => {
observer.onMutationUpdate(action);
});
this.mutationCache.notify({
mutation: this,
type: 'updated',
action
});
});
}
}
exports.Mutation = Mutation;
function getDefaultState() {
return {
context: undefined,
data: undefined,
error: null,
failureCount: 0,
isPaused: false,
status: 'idle',
variables: undefined
};
}