Пользователь
0,0
рейтинг
22 октября 2015 в 11:36

Разработка → Изучение React — для чего, откуда, как? tutorial

С чего начать изучение новой библиотеки или фрейморка? Сразу же найти статью на Хабре и с головой погрузиться в пучину практических примеров? Или сначала тщательно изучить официальную и неофициальную документацию, прежде чем перейти к практике? Именно между этими вопросами будет метаться ваше сознание, когда вы решите узнать, что же такое ReactJS. Чтобы желание учиться не умерло, как знаменитый ослик, обязательно загляните под капот.

Готовь сани летом а телегу зимой


Мало кто на перед задумывается о том, как готовое приложение будет работать на боевом сервере. Обычно эти вопросы решаются в самом конце, когда код уже написан, и пути назад нет. Именно поэтому прежде чем заняться изучением самой библиотеки, определитесь с вопросами компиляции кода вашего будушего творения. Варианта тут два. Для учебы, или скажем, демоверсии сайта, подойдет вариант компиляции на стороне клиента. Ничего делать не надо, все за вас сделает браузер, “на лету” так сказать. Но вот для готового продукта, я бы посоветовал настроить компиляцию на стороне сервера. Благо инструментов для этого предостаточно. Тут вам и Babel , и NodeJS или Webpack.

Детство, детство ты куда ушло


Ну вот, с вопросами компиляции разобрались. Перейдем к изучению? Нет, еще рано. React реализует модульный подход для построения приложений. Что это значит? Представьте себе конструктор. Не тот конструктор, что внутри класса, а простой детский конструктор. Точно так же, как из маленьких блоков в детстве вы строили свои шедевры, вы будете строить приложение из React компонентов. Так играть даже интересней, поскольку компоненты создаете тоже вы сами. Прелесть модульного подхода заключается в том, что создав и протестировав такой компонент один раз, вы легко можете использовать его и в других своих приложениях. Поэтому мой вам совет: создавайте отдельные файлы для каждого из них, а потом просто подключайте туда, куда надо. Вроде все просто, но это не совсем так. Приложение получиться пустым, мертвым, если его компоненты не будут “общаться” между собой. А это как раз и есть самое сложное и интересное.

Ну дайте же мне поработать!


Вижу, что ваше желание учиться тает на глазах. Поэтому открываем документацию и переходим от слов к делу. Все, что нам нужно для учебы, находиться на официальном сайте библиотеки. Правда информация структурирована плохо. Помочь вам не потеряться в этом хаосе — вот главная задача этой статьи.
Как вы уже поняли, основной задачей при разработке приложений на React, является разбивание страницы на блоки и создание компонентов, которые реализовывали бы функционал каждого из них.
Для начала создайте «статическую» версию вашего компонента. Очень рекомендую обратить внимание на JSX.

var LoginForm = React.createClass({

render: function() {
        
        return (
                <form id="login-form">
                    <input type="text" id="login" placeholder="login" />
                    <input type="password" id="password" placeholder="password" />
                    <button type="submit">Login</button>
                </form>
        )
}
});

React.render( <LoginForm />, document.getElementById('example'));

Оценили преимущества JSX синтаксиса? Тогда идем дальше. Добавим немного «интерактивности». Интерфейс компонента будет перерисовываться автоматически при изменении каких-либо данных внутри этого компонента. К ним относятся:

  • State (состояние) — набор данных, которые отражают состояние компонента в конкретный момент времени.
  • Props (свойства) — данные, передаваемые компоненту через атрибуты.

Поэтому все сводится к банальному изменению состояния или свойств в ответ на действия пользователя.

var LoginForm = React.createClass({
    getInitialState: function(){
        /* начальное состояние компонента */
        return { errorCode: 0, errorMessage: '', loginActions: [] };
    },

    doLogin: function(event) {
        event.preventDefault();
        
        var successLogin = (Math.random() >= 0.5) ? true : false;
        var actions = this.state.loginActions;

        if (!successLogin) {
            actions.push('Login failure');

            /* изменяем состояние компонента при возникновении ошибки */        
            this.setState({errorCode: 1, errorMessage: 'Error while login.', loginActions: actions});
        }
        else {
            actions.push('Login success');
            
            this.setState({errorCode: 0, errorMessage: '', loginActions: actions});
        }
    },

    render: function() {

        /* учитываем состояние компонента при отрисовке */
        var errorMessage = (this.state.errorCode > 0) ? this.state.errorMessage : '';
        var errorStyle = (this.state.errorCode > 0) ? {display: 'block'} : {display: 'none'};

        return (
            <div>
                <form id="login-form">
                    <div>
                        <input type="text" id="login" placeholder="login" />
                        <input type="password" id="password" placeholder="password" />
                    </div>
                    <div>
                        <button type="submit" onClick={this.doLogin}>Login</button>
                    </div>
                    <div style={errorStyle}>
                        <span style={{color: '#d9534f'}}> {errorMessage}</span>
                    </div>
                </form>
                
                <div className="actions-list">

                     /* передаем данные потомку через атрибут actions */
                    <ActionsList actions={this.state.loginActions} />
                </div>
            </div>
        )
    }
});

var ActionsList = React.createClass({

    render: function() {

        /* данные, полученые от родителя доступны через this.props */
        return (
            <ol>
                {
                    this.props.actions.map(function(action) {
                        return <li>{action}</li>;
                    })                
                }
            </ol>
        )
    }
});

React.render( <LoginForm />, document.getElementById('example'));

Как вы уже поняли, React значительно отличается от других библиотек. Поэтому нет ничего удивительного в том, что при работе с элементами формы тоже есть свои особенности, которые могут добавить вам изрядную долю седых волос на голове. Элементы формы делятся на два типа:

  • Не контролируемые — элементы, для которых свойство value не установлено.
  • Контролируемые — элементы, в которых установлено свойство value.

Давайте установим начальное значение для элементов ввода, и попробуем ввести что-нибуть:

<input type="text" id="login" placeholder="login" value=”admin” />

<input type="password" id="password" placeholder="password" value=”admpass” />

Как видим, у нас ничего не получилось. Теперь React «контролирует» эти элементы и нам нужно писать для них собственые обработчики изменений. Представляеке сколько это работы, писать функции-обработчики для каждого из контролируемых елементов? Мама не горюй! Но добрые дяденьки из Facebook не оставили нас в беде и добавили в React возможность использовать примеси (mixins). Да еще и несколько хороших дополнений (addons) подкинули.

var LoginForm = React.createClass({
    /* подключаем примеси */
    mixins: [React.addons.LinkedStateMixin],
    
    getInitialState: function(){
        return { errorCode: 0, errorMessage: '', loginActions: [], defaultLogin: 'admin', defaultPassword: 'password' };
    },

    doLogin: function(event) {
        event.preventDefault();
        
        var successLogin = (Math.random() >= 0.5) ? true : false;
        var actions = this.state.loginActions;

        if (!successLogin) {
            actions.push('Login failure');
        
            this.setState({errorCode: 1, errorMessage: 'Error while login.', loginActions: actions});
        }
        else {
            actions.push('Login success');
            
            this.setState({errorCode: 0, errorMessage: '', loginActions: actions});
        }
    },

    render: function() {
        var errorMessage = (this.state.errorCode > 0) ? this.state.errorMessage : '';
        var errorStyle = (this.state.errorCode > 0) ? {display: 'block'} : {display: 'none'};

        return (
            <div>
                <form id="login-form">
                    <div>
                        /* используем функцию из примеси и спецыальный атрибут valueLink */
                        <input type="text" ref="login" placeholder="login" valueLink={this.linkState('defaultLogin')} />
                        <input type="password" ref="password" placeholder="password" valueLink={this.linkState('defaultPassword')} />
                    </div>
                    <div>
                        <button type="submit" onClick={this.doLogin}>Login</button>
                    </div>
                    <div style={errorStyle}>
                        <span style={{color: '#d9534f'}}> {errorMessage}</span>
                    </div>
                </form>
                
                <div className="actions-list">
                    <ActionsList actions={this.state.loginActions} />
                </div>
            </div>
        )
    }
});

var ActionsList = React.createClass({

    render: function() {
        
        return (
            <ol>
                {
                    this.props.actions.map(function(action) {
                        return <li>{action}</li>;
                    })                
                }
            </ol>
        )
    }
});

React.render( <LoginForm />, document.getElementById('example'));

Если вы думаете, что «сюрпризов» больше не осталось, то очень сильно ошибаетесь. Вот вам задачка: как организовать двунаправленный обмен данными между компонентами? Ведь свойства передаются только в одном направлении — от отца к потомкам. А наоборот? Как потомок может влиять на данные своего родителя? Очень просто:

var LoginForm = React.createClass({
    mixins: [React.addons.LinkedStateMixin],
    
    getInitialState: function(){
        /* мы хотим, чтобы потомок мог изменять состояние родителя, в часности, очищать масив loginActions */
        return { errorCode: 0, errorMessage: '', loginActions: [], defaultLogin: 'admin', defaultPassword: 'password' };
    },

    clearActionList: function() {
          /* для этого  в родителе создаем функцию, которая очищает loginActions */
          this.setState({loginActions: []});
    },
    
    doLogin: function(event) {
        event.preventDefault();
        
        var successLogin = (Math.random() >= 0.5) ? true : false;
        var actions = this.state.loginActions;

        if (!successLogin) {
            actions.push('Login failure');
        
            this.setState({errorCode: 1, errorMessage: 'Error while login.', loginActions: actions});
        }
        else {
            actions.push('Login success');
            
            this.setState({errorCode: 0, errorMessage: '', loginActions: actions});
        }
    },

    render: function() {
        var errorMessage = (this.state.errorCode > 0) ? this.state.errorMessage : '';
        var errorStyle = (this.state.errorCode > 0) ? {display: 'block'} : {display: 'none'};

        return (
            <div>
                <form id="login-form">
                    <div>
                        <input type="text" ref="login" placeholder="login" valueLink={this.linkState('defaultLogin')} />
                        <input type="password" ref="password" placeholder="password" valueLink={this.linkState('defaultPassword')} />
                    </div>
                    <div>
                        <button type="submit" onClick={this.doLogin}>Login</button>
                    </div>
                    <div style={errorStyle}>
                        <span style={{color: '#d9534f'}}> {errorMessage}</span>
                    </div>
                </form>
                
                <div className="actions-list">
                     /* и передаем эту функцию потомку через атрибут, точно так же, как и данные */
                    <ActionsList actions={this.state.loginActions} clearActions={this.clearActionList} />
                </div>
            </div>
        )
    }
});

var ActionsList = React.createClass({

    render: function() {
        return (
            <div>
                /* здесь мы можем изменять состояния родителя, вызывая соответствующую функцию - this.props.clearActions */
                <button onClick={this.props.clearActions}> Clear list </button>
                <ol>
                    {
                        this.props.actions.map(function(action) {
                            return <li>{action}</li>;
                        })                
                    }
                </ol>
            </div>
        )
    }
});

React.render( <LoginForm />, document.getElementById('example'));

Делу время, потехе час!


Ну вот. Теперь действительно все. Первый этап пройден и я рад приветствовать вас в рядах новоиспеченных реакторов. Стоит ли ReactJS потраченного на него времени — каждый решает для себя. Пройдено только пол пути. Для кого-то эта дорога была легкой, для кого-то — не очень. Кто-то пойдет дальше, а кто-то остановиться. И я очень надеюсь, что моя статья будет хорошим подспорьем новичкам.
@kambur
карма
0,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (59)

  • +7
    Вам удобно писать разметку в JS коде? Можно ли ее выносить в темплейты или как бороться с этим?
    • 0
      Вопрос хороший. Честно говоря, я пока над этим не задумывался.
      • 0
        Пока пробую JSX
        • +2
          JSX, как я понимаю, представляет собой псевдо разметку, которую читает IDE.
          Т.е. проблема разделения вьюхи и Js остается. + Если IDE не поддерживает JSX то все совсем не удобно.
          Есть методы как с этим бороться?
          • 0
            Можно использовать SublimeText или Atom.io
          • 0
            Т.е. проблема разделения вьюхи и Js остается

            По каким-то причинам Вы считаете, что View — это не JS? React представляет собой идею функционального подхода к програмимрованию пользовательских интерфейсов, соответственно не имеет ничего общего с MVC и стараться «подбить» его к знакомой терминологии не имеет смысла.

            Если IDE не поддерживает JSX то все совсем не удобно.

            Ну, во-первых, уже, наверное, не осталось IDE, которые не поддерживают JSX, а во-вторых Вы всегда можете писать без JSX через React.DOM.div и т.п.
            • 0
              Что бы вы не говорили, но единственная задача view это отрисовка. Нельзя мешать представление с моделью.
              • +2
                Конечно, React вообще не должен ничего знать о данных, которые поступают в его компоненты! Поэтому и появился flux — чтобы решить проблему работы с данными и коммуникацией между компонентами. Довольно тяжело сейчас говорить о React без упоминания Flux.
              • +2
                Раньше как и вы мыслил. Пришло время адаптироваться. И я понял что так намного удобнее. Нет больше трёх разных сущностей как html css js. Есть одна — веб компонент. Для этого мы и держим все в одной папке, составляющие компонента. Держать разметку в js отличная идея, удобно. Как правило разметка не большая. Если у вас вёрстки в компоненте на целую страницу, значит что то пошло не так !)
                • 0
                  Не буду с вами спорить, если вам удобно… Но архитектурно это не правильно, вас поставили в рамки которые противоречат здравому смыслу. Все это выглядит как костыль. Напоминает сервлеты от которых отказались, в плане верстки, уже очень давно.
                  • 0
                    Яснопонятно
                • 0
                  Мысль про веб компонент отличная — в одной папке html, css, js. Я её поддерживаю.
                  Но хотелось бы держать все три элемента в трёх разных файлах: *.html, *.css, *.js соответственно.
          • +1
            Я не уверен, что в случае с React есть необходимость разделять код от от представления.
            Но тут все зависит от индивидуальных предпочтений.
            Если разработчик создает много компонентов и помещает все это в один файл, получается каша. Тогда есть смысл как-то навести порядок и разделить js от html
            Но я сторонник модульного подхода к разработке. Один компонент — один маленький блок html + код реализации логики.
          • 0
            По большому счету можно вобще отказаться от html в компонентах и писать все на чистом React.
            В таком случае ваши компоненты будут универсальными.
    • 0
      Я думаю, что разработчикам в будущем не помешает
      1. Добавить поддержку темплейтов
      2. Улучшить работу со свойствами (скажем придумать объект parent через который потомок может изменять состояние родителя)
      • +3
        1. О каких темплейтах Вы говорите?
        2. Никакого two-way data-binding. Все свойства передаются от родителя к потомку и никак иначе. А вообще, для работы с данными в React существует множество библиотек (например, redux)
        • 0
          По второму пункту, так на секундочку — https://www.npmjs.com/package/react-binding
          • 0
            «Так на секундочку» — 115 скачек за последний месяц + 14 звёзд на GH и 2 issue за 5 месяцев. Я бы не полагался на подобную библиотеку при проектировании приложения, особенно если она идёт вразрез оф. идеологии.

            Видимо, я не совсем ясно выразился: разумеется, сделать можно всё что угодно — это js, в конце концов. Вы так же можете использовать родной хак: facebook.github.io/react/docs/two-way-binding-helpers.html, однако даже на этой странице написано, что React спроектирован как one-way data flow система.
      • 0
        Шаблоны вполне можно делать в виде методов, получающих данные и возвращающих верстку, например.
        • +1
          Это называется «dumb components» и в React 0.14 реализуется с помощью обычных функций:

          // A functional component using an ES2015 (ES6) arrow function:
          var Aquarium = (props) => {
            var fish = getFish(props.species);
            return <Tank>{fish}</Tank>;
          };
          
          // Or with destructuring and an implicit return, simply:
          var Aquarium = ({species}) => (
            <Tank>
              {getFish(species)}
            </Tank>
          );
          
          // Then use: <Aquarium species="rainbowfish" />
          

          Взято из пресс-релиза 0.14
          • 0
            Dumb component, насколько я понимаю, это просто обертка в виде кастомного тега, содержащая верстку и не содержащая внутренней логики. Что-то типа:
            <div>{this.props.children}</div>
            
            Компоненты имеет смысл делать только если они переиспользуются, а внутри компонента шаблон вывода элемента можно сделать кучей разных способов.
            • 0
              Основная идея, «пропитывающая» реакт — композиция элементов. Т.е. «шаблон вывода» в Вашем понимании составляется из маленьких dumb components, которые при аггрегации образуют то, что Вам нужно.

              Разумеется, где-то вверху будет находится smart component, который будет оркестрировать весь процесс: забирать данные из какого-нибудь хранилища (будь то что-то самописное, redux store или что либо ещё) и передавать эти данные в ваши dumb components и, возможно, содержать логику а-ля «если количество записей больше нуля, показывать dumb component со списком записей, в противном случае показывать заглушку с сообщением об отсутствии записей». По факту весь реакт — это один большой шаблон, если так посмотреть :)
              • 0
                Я поддерживаю, в реакте есть ровно все, что необходимо и следует придерживаться композитных компонентов и чистых функций
    • +1
      Это такая «фишка» реакта, мне вначале казалось неудобным, но быстро привыкаешь и начинаешь даже любить эту схему. А вообще можно использовать jade шаблоны. Посмотрите на react-jade.
      • +9
        Любить разметку в JS? :D
        • 0
          Выходит что код разделен на маленькие модули всегда, и очень часто нужно менять разметку вместе с JS, в данном случае проще ничего не забыть ибо все на виду
          • +2
            Возможно это дело привычки.
        • +6
          На мой взгляд, вычленять разметку из JSX не стоит. Почему?
          1) Метод render у меня ещё ни разу не оказывался больше высоты экрана (обычно вообще строк 12-20).
          2) В шаблоне логики вообще нет, никаких условных конструкций или циклов. Вся логика реализована выше в самом JS.
          3) Желательно видеть, какие ноды какими ref я подписал, или какой метод вызвать при каком-то событии. Значит всё должно быть под рукой, а не переключаться между двумя файлами.

          Причины за «выделение шаблона в отдельный файл» мне в голову не приходят. Станет хуже.

          P.S.
          По началу тоже думал, что html в JS — это какая-то дикость. Но изменил свою точку зрения. По поводу поддержки IDE — работал с jsx в Sublime без какой либо поддержки React, подсветки синтаксиса JS вполне хватало.
          • 0
            Спасибо за подробный ответ.
          • 0
            Согласен, то что с первого взгляда кажется дикостью, после месяца подсаживает на именно такой стиль написания кода. Все что можно вынести в другой компонент выносится и html не выглядит грамоздко.
        • –3
          Может быть человек давно начинал с PHP и с тех пор полюбил подход мешать код и разметку вместе. Фейсбук вот тоже с PHP дружит, вот и сделали в своем родном стиле.
    • 0
      Выносить можно, так как по сути в итоге там обычное JS-выражение. Т.е. его можно записывать в переменную, экспортировать из модуля и т.д. На практике, это обычно не нужно, так как если HTML-кода становится очень много, значит компонент плохой, а небольшое количество HTML-кода в методе render не мешает.

      Так же в TypeScript запилили поддержку JSX (TSX) с проверкой типов, компиляцией и подсветкой. Пока сыровато, но обещает быть очень вкусно.

      В целом, другого пути, кроме смешения JS и HTML, особо и нет, выдумывать тонны селекторов и писать отдельно обработчики событий больше нет желания, спрашивается, с чего начинали…
    • 0
      Во перых это не JS, а JSX
      И по сути react это и есть умный темплейтовый движок, так что любые файлы с расширением .jsx в проекте написанном на реакте по своей сути являются темплейтами, а уже как фреймворк отвечающий за логику можно брать до пустим backbone.
      • 0
        Я могу ошибаться (тогда поправьте), я думал что JSX это псевдо-разметка, а JS это клей который обеспечивает функциональность компоненты. И имел ввиду смешение первого и второго.
        • +1
          JUST THE UI
          Lots of people use React as the V in MVC. Since React makes no assumptions about the rest of your technology stack, it's easy to try it out on a small feature in an existing project.


          Из офф сайта реакта, даже разработчики утверждают что большенство людей используют его как View в MVС.
          По всей своей сути react это как бы описание UI объекта.
          И для того что бы не смешивать реальный JS и не тулить туда еще и разметку, разработчиками был выбран альтернативный формат .jsx который и решает данную задачу.
          То есть в любом случае в Ваших jsx файлах будет как минимум не много js-подобного кода и xml-разметка (по тому что это точно не html).
          Но логику и обработку данных все же лучше выносить в контроллеры и модельки Вашего приложения, дабы View оставался максимально чистым.
    • 0
      JSX используется в качестве препроцессора для улучшения «читабельности» кода. «Под капотом» оно транслируется в ES5-совместимый формат, т.е.

      render() {
        return <div>hello</div>;
      }
      


      будет транслирован в

      render() {
        return React.DOM.div(null, 'hello');
      }
      


      Разумеется, вы можете использовать вторую версию без каких-либо препроцессоров. Об это подробнее на оф. сайте. Так же, в версии 0.14 работа с DOM вынесена в отдельную библиотеку react-dom.
    • 0
      Попробуйте RequireJS с плагином text.
    • 0
      По факту, это не то чтобы разметка. Это язык описания дерева UI, т.е. он включает в себя, помимо тегов, вызовы компонент. А в случае с каким-нибудь React Native, там вообще нет привычных тегов.
    • +2
      Не нужно выносить разметку. Она связана с логикой приложения, и это не coupling, это cohesion. Компонент — это логика и представление. Тут SRP не по принципу «ты определяешь представление (как будет выглядеть какой-то элемент)» и «ты определяешь логику (как взаимодействовать с конкретным элементом)», а по принципу «ты инкапсулированный компонент, в тебе представление и логика его отображения».
      Тут правда есть нюанс с тем, как верстальщика с этим работать заставить. У нас процесс построен, что верстальщик концептуально верстает элементы управления, а мы уже из этой вёрстки создаём компоненты, так что у нас нет проблемы.
      На эту тему есть совершенно прекрасный доклад Александра Соловьева Как писать UI без боли. Вообще у него совершенно потрясающие видео на YouTube, очень советую и другие посмотреть :)
  • +1
    Если уж все равно приходится использовать browserify или webpack то можно было бы писать на es2015/es6, babel (babelify) отлично понимает jsx и в самой документации реакта есть примеры как можно использовать нативные классы в создании компонентов. Если интересно могу показать примеры gulpfile для сборки.
  • +3
    Как потомок может влиять на данные своего родителя? Очень просто:

    и далее простыня кода без комментариев.
    Вы бы хоть полужирным выделили изменения по отношению к предыдущей простыне.
    • 0
      Вы абсолютно правы. Приношу свои извинения и бегу писать коменты.
  • 0
    Вот вам задачка: как организовать двунаправленный обмен данными между компонентами?

    Может лучше сразу к Flux привыкать?
    Вроде даже в Angular 2 от двунаправленного обменами данных решили отказаться?
    • 0
      И в Angular 2, и в Ember 2 тоже (и там, и там — плотно советуясь с командой React), и на Angular 1 тоже в итоге для больших приложений получается удобнее писать (субъективно), когда есть явная передача данных «туда» и «обратно».

      Однако, часто бывает удобен и 2-way-binding, но надо понимать, когда его лучше использовать (в Aurelia он хорошо сделан и лишен недостатков оного в Angular 1) — тут создатели разных фреймворков вроде как сошлись во мнении, что правильный 2-way-binding — это сахар над one-way-binding для отдельных случаев (именно такой подход используется в ng2 с его жуткими "([...])" скобками в шаблонах и похожий в Aurelia с его «адаптивными байндингами»).
    • 0
      Flux — я за!!!
  • +7
    Эта статья — отличный пример того, как не надо писать статьи. В начале 3 абзаца переливания из пустого в порожнее.
    Перейдем к изучению? Нет, еще рано. React реализует модульный подход для построения приложений. Что это значит? Представьте себе конструктор. Не тот конструктор, что внутри класса, а простой детский конструктор.

    Вы вообще свой текст перечитывали? Нет, перечитывали. Может перечитаете? Нет, еще рано. Постойте. Нет, читайте. А, блин, уже поздно, Евгений Ваганыч недоволен.
    Потом несколько кусков кода без комментариев. Думаете, в интернете мало примеров кода на React, вся надежда на вас?
    Тем читателям, кто осваивает React с нуля советую начать с официальной документации, там все понятно и подробно.
    • 0
      Тут я с вами абсолютно не согласен. Для вас, как опытного программиста, статья действительно может показаться убожеством. Просто она предназначена не для вас. Я не преследовал цель создать первоклассный туториал, их и так как листьев на деревьях. А что делать человеку, который только, только делает первые шаги по пути фронт-енд разработки? Кто ему подскажет, кто направит?
      Меня сильно раздражают напыщенные индюки вроде вас, которые только и умеют критиковать. Нет чтобы помочь, подсказать и сделать статью лучше. Ведь конечная цель — помощь людям!
      • +2
        Это спорно, кто из нас двоих больше подходит под определение «напыщенного индюка». В любом случае, словоблудие и малое количество информации вряд ли помогут начинающему программисту. Ваша статья не подсказывает и не направляет.
        • 0
          Поживем — увидим.
          Как говорил Максим Горький:
          … Мудрость жизни всегда глубже и обширнее мудрости людей.
  • 0
  • 0
    Может кто-то посоветует приличные компаненты для работы с формами? Валидация, локализация, кастомизация и т.п.
    А так же кучу-кучу всяких компонентов для этих форм.
    Может кому-то удалось локализировать DatePicker из Material UI?
    • 0
      Все что есть все тут github.com/enaqx/awesome-react
      • 0
        Спасибо, про это я знаю…
        Как по мне — беда-беда…
  • +3
    Обзор двух-летней давности )
    На реакте сейчас пишут как-то вот так teropa.info/blog/2015/09/10/full-stack-redux-tutorial.html
    • 0
      Отличная статья, кстати говоря.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.