Files
edx-platform/common/static/js/src/ReactRenderer.jsx
2018-11-12 18:13:51 +05:00

67 lines
2.0 KiB
JavaScript

import React from 'react';
import ReactDOM from 'react-dom';
class ReactRendererException extends Error {
constructor(message) {
super(`ReactRendererException: ${message}`);
Error.captureStackTrace(this, ReactRendererException);
}
}
export class ReactRenderer {
constructor({ component, selector, componentName, props = {} }) {
Object.assign(this, {
component,
selector,
componentName,
props,
});
this.handleArgumentErrors();
this.targetElement = this.getTargetElement();
this.renderComponent();
}
handleArgumentErrors() {
if (this.component === null) {
throw new ReactRendererException(
`Component ${this.componentName} is not defined. Make sure you're ` +
`using a non-default export statement for the ${this.componentName} ` +
`class, that ${this.componentName} has an entry point defined ` +
'within the \'entry\' section of webpack.common.config.js, and that the ' +
'entry point is pointing at the correct file path.',
);
}
if (!(this.props instanceof Object && this.props.constructor === Object)) {
let propsType = typeof this.props;
if (Array.isArray(this.props)) {
propsType = 'array';
} else if (this.props === null) {
propsType = 'null';
}
throw new ReactRendererException(
`Invalid props passed to component ${this.componentName}. Expected ` +
`an object, but received a ${propsType}.`,
);
}
}
getTargetElement() {
const elementList = document.querySelectorAll(this.selector);
if (elementList.length !== 1) {
throw new ReactRendererException(
`Expected 1 element match for selector "${this.selector}" ` +
`but received ${elementList.length} matches.`,
);
} else {
return elementList[0];
}
}
renderComponent() {
ReactDOM.render(
React.createElement(this.component, this.props, null),
this.targetElement,
);
}
}