Современный мир программирования, а особенно веб и javascript уже давно не тот и имеет очень большое колличество инструментов для той или иной задачи. В сегодняшнем посте я хотел бы рассказать как скрестить мощь AngularJS и молниеносность отображения view – Facebook React.
Всем известно, что когда мы генерируем коллекцию во view через Angular, то каждый элемент этой коллекции становится observable. Я конечно понимаю и знаю что есть определенный набор библиотек и решений как это обойти, но сегодня речь не об этом. Что же дает нам React? Ну одно из его преимуществ, это jsx синтаксис, который есть не что иным как html в javascript. Также есть возможность создавать reusable компоненты, наследовать их и использовать всю мощь что позволяет делать эта библиотека. Что же приступим.
Первым делом создадим простой проект с банальным названием ng-with-react. Для установки библиотек я воспользуюсь bower. С помощью него установим AngularJS, ReactJS и Twitter bootstrap дабы наше приложение имело хоть какой-то презентабельный вид. Создадим main.js и index.html которые будут иметь код:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>AngularJS with Facebook react</title>
<link rel="stylesheet" href="app/vendor/bootstrap/dist/css/bootstrap.css"/>
<style>
.user-list .user-item {
border-left: none;
border-right: none;
}
.user-list .user-item:last-child {
border-bottom: none;
}
</style>
<script src="app/vendor/angular/angular.js"></script>
<script src="app/vendor/react/react.js"></script>
<script src="app/main.js"></script>
</head>
<body ng-app="app">
<div class="container" ng-controller="MainCtrl as main">
<div class="page-header">
<h1>A experiment with AngularJS and ReactJS</h1>
</div>
<div class="panel panel-default">
<div class="panel-heading">Just AngularJS</div>
<ul class="list-group">
<li class="list-group-item" ng-repeat="user in users" ng-click="main.getUser(user)">
{{ user.firstName }} - {{ user.lastName }}
</li>
</ul>
</div>
</div>
</body>
</html>
И
(function(ng, React)
var app = ng.module('app', []);
var UserFactory = function() {
var users = [
{id: 1, firstName: "Denis", lastName: "Stoyanov", age:26},
{id: 2, firstName: "Alex", lastName: "Alexeev", age:24},
{id: 3, firstName: "Peter", lastName: "Petrov", age:21},
{id: 4, firstName: "Ivan", lastName: "Ivanov", age:20}
];
return {
users: users
};
};
var UserCtrl = function($scope, $log, User) {
$scope.users = User.users;
this.getUser = function(user) {
$log.info('A selected user %O', user);
};
};
app.factory('User', [UserFactory]);
app.controller('MainCtrl', ['$scope', '$log', 'User', UserCtrl]);
return app;
})(angular, React);
Соответственно.
Что у нас есть в арсенале сейчас. Мы имеем простейшее приложение на ng в котором есть простейший контроллер и сервис, который отдает фейковые данные. На стороне представления мы имеем простейший список, который рендерит наши данные. Также у нас есть обработчик по клику на элемент, который записывает юзера в консоль. Все довольно просто и легко.
Теперь давайте создадим новую директиву для отображения этих же данных, но только через ReactJS. Как подобает в лучших домах Парижа, нам стоит использовать директивы для манипулирования DOM. Для начала создадим React class для рендеринга списка. Его код будет выглядет примерно так:
var UserList = React.createClass({
displayName: "UserList",
render: function() {
var users = this.props.scope.users;
var scope = this.props.scope;
var userList = users.map(function(user, index, array) {
var clickHandler = scope.$apply.bind(scope,
scope.userSelected.bind(null, {user: user}));
return React.DOM.li({ className: "user-item list-group-item", onClick: clickHandler },
[user.firstName, user.lastName].join(' - '));
});
return React.DOM.ul( {className:"user-list list-group"}, userList);
}
});
Как можно заметить в свойствах React есть ряд переменных, которых нам надо будет передать путем простой передачи scope в React class. Также создадим директиву, которая будет использовать этот класс как представление.
var UserDirective = function() {
return {
restrict: 'AE',
scope: {
users: '=',
userSelected: '&'
},
link: function(scope, element, attrs) {
scope.$watchCollection('users', function() {
React.renderComponent(UserList({scope: scope}), element[0]);
});
}
};
};
app.directive('userList', UserDirective);
В ней видно, что будем мы ее использовать как элемент или же аттрибут, в нее будут переданы данные с юзерами и функция для вывода юзера в консоль. Чтобы наше представление отображалось при изменении коллекции и создадим простейший watcher и на его изменения будет перерисовывать наше представление. И наконец мы срендерим наш React class в тот елемент, на который был повешен аттрибут user-list. В index.html после рендеринга на Angular добавим такой код:
<div class="panel panel-default">
<div class="panel-heading">AngularJS with ReactJS</div>
<div user-list users="users" user-selected="main.getUser(user)"></div>
</div>
Вот такими простыми манипуляциями мы связали Angular и React. Приложение простейшее, но оно дает понять концепт и в дальнейшем можно усложнять. По моим тестам при 2000 елементов view на React было в 5 раз быстрее чем на Angular.
На скриншоте мы можем видеть, что у view на React нет байндингов в отличии от ReactJS.
Также мы можем посмотреть, что нам сгенерировал React.
Надеюсь мой эксперимент будет кому-то полезен. Я считаю, что надо компоновать решения по их возможностям и если писать на ReactJS представления удобней и в отображении они быстрее, то я буду делать так.
Если есть какие-то нюансы, welcome в комментарии =)
Автор: xGromMx