13 March 2014

AngularJS и ReactJS или как сделать ваше приложение быстрее

JavaScriptAngularReactJS
Современный мир программирования, а особенно веб и javascript уже давно не тот и имеет очень большое количество инструментов для той или иной задачи. В сегодняшнем посте я хотел бы рассказать как скрестить мощь AngularJS и молниеносность отображения view – Facebook React.

Всем известно, что когда мы генерируем коллекцию во view через Angular, то каждый элемент этой коллекции становится observable. Я конечно понимаю и знаю что есть определенный набор библиотек и решений как это обойти, но сегодня речь не об этом. Что же дает нам React? Ну одно из его преимуществ, это jsx синтаксис, который есть не что иным как html в javascript. Также есть возможность создавать reusable компоненты, наследовать их и использовать всю мощь что позволяет делать эта библиотека. Что же приступим.

Первым делом создадим простой проект с банальным названием ng-with-react. Для установки библиотек я воспользуюсь bower. С помощью него установим AngularJS, ReactJS и Twitter bootstrap дабы наше приложение имело хоть какой-то презентабельный вид. Создадим index.html и main.js которые будут иметь код:

<!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 нет байндингов в отличии от AngularJS.



Также мы можем посмотреть, что нам сгенерировал React.



Надеюсь мой эксперимент будет кому-то полезен. Я считаю, что надо компоновать решения по их возможностям и если писать на ReactJS представления удобней и в отображении они быстрее, то я буду делать так.
Если есть какие-то нюансы, welcome в комментарии =)

Код примера Source
Tags:angularjsjavascriptreact
Hubs: JavaScript Angular ReactJS
+20
50.1k 206
Comments 14
Top of the last 24 hours