Repository URL to install this package:
|
Version:
1.2.20 ▾
|
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = withJob;
var _react = _interopRequireDefault(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _exotic = require("exotic");
var _identifier = require("../../identifier");
var _utils = require("./utils");
var _jsxFileName = "/Users/michaelfrohberg/Training/mono/packages/modules/SSR/react-jobs/withJob.js";
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
const validSSRModes = ['resolve', 'defer', 'boundary'];
const neverWorkAgain = () => false;
function DefaultErrorComponent(props) {
if (props.error) {
throw props.error;
}
} // @todo @perf
// const SEALED_STATE = {
// data: EMPTY_OBJ,
// error: undefined,
// completed: undefined,
// }
// Object.seal(SEALED_STATE)
// this.state = SEALED_STATE
function withJob(config) {
if ((0, _exotic.isObj)(config)) {
throw new Error('You must provide a config object to withJob');
}
const work = config.work,
LoadingComponent = config.LoadingComponent,
_config$ErrorComponen = config.ErrorComponent,
ErrorComponent = _config$ErrorComponen === void 0 ? DefaultErrorComponent : _config$ErrorComponen,
_config$serverMode = config.serverMode,
serverMode = _config$serverMode === void 0 ? 'resolve' : _config$serverMode,
_config$shouldWorkAga = config.shouldWorkAgain,
shouldWorkAgain = _config$shouldWorkAga === void 0 ? neverWorkAgain : _config$shouldWorkAga;
if ((0, _exotic.isFunction)(work) === false) {
throw new Error('You must provide a work function to withJob');
}
if (validSSRModes.indexOf(serverMode) === -1) {
throw new Error('Invalid serverMode provided to asyncComponent');
}
const env = typeof window === 'undefined' ? 'node' : 'browser';
return function wrapWithJob(WrappedComponent) {
let id;
class ComponentWithJob extends _react.default.Component {
constructor(_props, context) {
super(_props, context); // Each instance needs it's own id as that is how we expect work to
// be executed. It is not shared between element instances.
this.resolveWork = props => {
let workDefinition;
this.setState({
completed: false,
data: null,
error: null
});
try {
workDefinition = work(props);
} catch (error) {
this.setState({
completed: true,
error
}); // Ensures asyncBootstrap stops
return false;
}
if ((0, _exotic.isPromise)(workDefinition)) {
// Asynchronous result.
return workDefinition.then(data => {
if (this.unmounted) {
return undefined;
}
this.setState({
completed: true,
data
});
if (this.context.jobs) {
this.context.jobs.register(id, {
data
});
} // Ensures asyncBootstrap continues
return true;
}).catch(error => {
if (this.unmounted) {
return undefined;
}
if (env === 'browser') {
setTimeout(() => {
if (!this.unmounted) {
this.setState({
completed: true,
error
});
}
}, 16);
} else {
// node
// We will at least log the error so that user isn't completely
// unaware of an error occurring.
// eslint-disable-next-line no-console
console.warn('Failed to resolve job'); // eslint-disable-next-line no-console
console.warn(error);
} // Ensures asyncBootstrap stops
return false;
});
} // Synchronous result.
this.setState({
completed: true,
data: workDefinition,
error: null
}); // Ensures asyncBootstrap continues
return true;
};
if (context.jobs) {
id = context.jobs.getNextId();
}
} // @see react-async-bootstrapper
asyncBootstrap() {
if (env === 'browser') {
// No logic for browser, just continue
return true;
} // node
return serverMode === 'defer' ? false : this.resolveWork(this.props);
}
componentWillMount() {
let result;
if (this.context.jobs) {
result = env === 'browser' ? this.context.jobs.getRehydrate(id) : this.context.jobs.get(id);
}
this.setState({
data: result ? result.data : null,
error: null,
completed: result != null
});
}
componentDidMount() {
if (!this.state.completed) {
this.resolveWork(this.props);
}
if (this.context.jobs && env === 'browser') {
this.context.jobs.removeRehydrate(id);
}
}
componentWillUnmount() {
this.unmounted = true;
}
componentWillReceiveProps(nextProps) {
if (shouldWorkAgain !== neverWorkAgain && shouldWorkAgain((0, _utils.propsWithoutInternal)(this.props), (0, _utils.propsWithoutInternal)(nextProps), // was calling an extra fn
this.state)) {
this.resolveWork(nextProps);
}
}
render() {
const _this$state = this.state,
data = _this$state.data,
error = _this$state.error,
completed = _this$state.completed;
if (error) {
return ErrorComponent ? _react.default.createElement(ErrorComponent, _extends({}, this.props, {
error: error,
__source: {
fileName: _jsxFileName,
lineNumber: 197
},
__self: this
})) : null;
}
if (!completed) {
return LoadingComponent ? _react.default.createElement(LoadingComponent, _extends({}, this.props, {
__source: {
fileName: _jsxFileName,
lineNumber: 201
},
__self: this
})) : null;
}
return _react.default.createElement(WrappedComponent, _extends({}, this.props, {
jobResult: data,
__source: {
fileName: _jsxFileName,
lineNumber: 203
},
__self: this
}));
}
}
ComponentWithJob.displayName = `WithJob(${(0, _identifier.toComponentName)(WrappedComponent)})`;
ComponentWithJob.contextTypes = {
jobs: _propTypes.default.shape({
getNextId: _propTypes.default.func.isRequired,
register: _propTypes.default.func.isRequired,
get: _propTypes.default.func.isRequired,
getRehydrate: _propTypes.default.func.isRequired,
removeRehydrate: _propTypes.default.func.isRequired
})
};
return ComponentWithJob;
};
}