Skip to content

Instantly share code, notes, and snippets.

@evanrs
Last active December 13, 2016 08:04
Show Gist options
  • Save evanrs/0c30bb9b858e95c32d0e8cc76c7662dd to your computer and use it in GitHub Desktop.
Save evanrs/0c30bb9b858e95c32d0e8cc76c7662dd to your computer and use it in GitHub Desktop.
Use React in an Angular app

ngReactComponent

Use React in an Angular app.

Bindings are automatically derived from propTypes.

const ngSuchComponent =
  ngReactBridge.create(SuchComponent);

Rational

There are a few solutions out there, I wanted to provide mine. I think mine provides exactly what anyone would need.

import React, { PropTypes } from 'react';
import ReactDOM from 'react-dom';
import { has, mapValues, omitBy, keys, pick } from 'lodash';
export const shape = {
$injector: PropTypes.object.isRequired,
$scope: PropTypes.object.isRequired,
$element: PropTypes.object.isRequired
}
class Bridge {
static $inject = ['$injector', '$scope', '$element'];
static propTypes = shape;
constructor($injector, $scope, $element) {
this.props = { $injector, $scope, $element };
}
$postLink() {
this.container = this.props.$element[0];
this.render();
}
$onChanges(changes) {
this.container && this.render();
}
$onDestroy() {
ReactDOM.unmountComponentAtNode(this.container)
}
createElement = (props) =>
<this.ComponentClass {...this.props} {...props}/>
render() {
this.instance =
this.createElement(pick(this, keys(this.bindings)));
try {
ReactDOM.render(this.instance, this.container);
}
catch(e) {
console.error('Unable to mount ReactBridge\n', e);
}
}
}
export function create(ComponentClass) {
let customBindings = ComponentClass.bindings || {};
let derivedBindings =
mapValues(
// Remove injected values
omitBy(ComponentClass.propTypes, (_, key) =>
/^[$](injector|scope|element)$/.test(key)),
// Set one way data binding
(propType) =>
// propTypes that are not required have an isRequired() method
`<${ ! has(propType, 'isRequired') ? '' : '?' }`
)
;
let bindings = { ...derivedBindings, ...customBindings }
return {
bindings,
controller: class ComponentBridge extends Bridge {
bindings = bindings
ComponentClass = ComponentClass;
}
}
}
export default {
create,
shape
}
{
"name": "ng-react-bridge",
"version": "1.0.0",
"description": "Use React in an Angular app.",
"main": "ngReactBridge.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://gist.github.com/0c30bb9b858e95c32d0e8cc76c7662dd.git"
},
"keywords": [
"angular",
"react"
],
"author": "Evan Schneider",
"license": "ISC",
"bugs": {
"url": "https://gist.github.com/0c30bb9b858e95c32d0e8cc76c7662dd"
},
"homepage": "https://gist.github.com/0c30bb9b858e95c32d0e8cc76c7662dd"
}
<such-component name="Evan"></such-component>
<such-component name="Evan" class="ng-isolate-scope">
<h1>
Hello Evan
</h1>
</such-component>
import React, { Component, PropTypes } from 'react';
import ngReactBridge from './ngReactBridge';
class SuchComponent extends Component {
static propTypes = {
// Bindings are derived from propTypes by default,
name: PropTypes.string.isRequired,
// These are the default props
...ngReactBridge.shape
};
// Override individual bindings with your own object
static bindings = {
name: '@'
}
render () {
return (
<h1>
Hello {this.props.name}
</h1>
)
}
}
module.component(
'suchComponent', ngReactBridge.create(SuchComponent));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment