NgReact

Intro

Facebook's React library is designed to be used as a view component atop other JavaScript frameworks. NgReact is a small library providing helpers and showing examples of achieving interoperability between React and Angular.

Motivation for this could be any of the following:

Installation

Via Bower:

bower install ngReact

Or via npm:

npm install ngreact

Usage

In your HTML:

<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/react/react.js"></script>
<script src="bower_components/ngReact/ngReact.min.js"></script>

Declare 'react' as a dependency of your Angular module:

angular.module('app', ['react']);

Examples

Features

reactComponent Directive

The reactComponent directive is a generic wrapper for embedding your React components.

With an Angular app and controller declaration like this:

angular.module('app', ['react'])
  .controller('helloController', function($scope) {
    $scope.person = { fname: 'Clark', lname: 'Kent' };
  });
        

And a React Component like this

/** @jsx React.DOM */
var HelloComponent = React.createClass({
  propTypes: {
    fname : React.PropTypes.string.isRequired,
    lname : React.PropTypes.string.isRequired
  },
  render: function() {
    return Hello {this.props.fname} {this.props.lname};
  }
});
app.value('HelloComponent', HelloComponent);
        

The component can be used in an Angular view using the react-component directive like so, where:

<body ng-app="app">
  <div ng-controller="helloController">
    <react-component name="HelloComponent" props="person" watch-depth="reference" />
  </div>
</body>
        

reactDirective Factory

The reactDirective factory, in contrast to the reactComponent directive, is meant to create specific directives corresponding to React components. In the background, this actually creates and sets up directives specifically bound to the specified React component.

If, for example, you wanted to use the same React component in multiple places, you'd have to specify <react-component name="yourComponent" props="props" /> repeatedly, but if you used reactDirective factory, you could create a yourComponent directive and simply use that everywhere.

The service takes the React component as the argument.

app.directive('hello', function(reactDirective) {
  return reactDirective(HelloComponent);
});
        

Alternatively you can provide the name of the component

app.directive('hello', function(reactDirective) {
  return reactDirective('HelloComponent');
});
        

This creates a directive that can be used like this:

<body ng-app="app">
  <div ng-controller="helloController">
    <hello fname="person.fname" lname="person.lname" watch-depth="reference" />
  </div>
</body>
        

The reactDirective service will read the React component propTypes and watch attributes with these names. If your react component doesn't have propTypes defined you can pass in an array of attribute names to watch. By default, attributes will be watched by value however you can also choose to watch by reference or collection by supplying the watch-depth attribute. Possible values are reference, collection and value (default).

app.directive('hello', function(reactDirective) {
  return reactDirective(HelloComponent, ['fname', 'lname']);
});
        

If you want to change the configuration of the directive created the reactDirective service, e.g. change restrict: 'E' to restrict: 'C', you can do so by passing in an object literal with the desired configuration.

app.directive('hello', function(reactDirective) {
  return reactDirective(HelloComponent, undefined, {restrict: 'C'});
});
        

Reusing Angular Injectables

In an existing Angular application, you'll often have existing services or filters that you wish to access from your React component. These can be retrieved using Angular's dependency injection. The React component will still be render-able as aforementioned, using the react-component directive.

Be aware that you can not inject Angular directives into JSX.

app.filter('hero', function() {
  return function(person) {
    if (person.fname === 'Clark' && person.lname === 'Kent') {
      return 'Superman';
    }
    return person.fname + ' ' + person.lname;
  };
});

/** @jsx React.DOM */
app.factory('HelloComponent', function($filter) {
  return React.createClass({
    propTypes: {
      person: React.PropTypes.object.isRequired,
    },
    render: function() {
      return Hello $filter('hero')(this.props.person);
    }
  });
});
        
<body ng-app="app">
  <div ng-controller="helloController">
    <react-component name="HelloComponent" props="person" />
  </div>
</body>
        

Jsx Transformation in the browser

During testing you may want to run the JSXTransformer in the browser. For this to work with angular you need to make sure that the jsx code has been transformed before the angular application is bootstrapped. To do so you can manually bootstrap the angular application. For a working example see the jsx-transformer example.

NOTE: The workaround for this is hacky as the angular bootstap is postponed in with a setTimeout, so consider transforming jsx in a build step.

Community

Maintainers

Contributors