Светлана Шаповалова, редактор «Нетологии», перевела статью Тайлера МакГинниса, в которой он перечислил основные моменты озарения, которые возникают при изучении React.
Одна из моих главных преподавательских задач — сделать так, чтобы у людей чаще случались моменты озарения. «Эврика!» — это момент внезапного прояснения, когда ранее непонятные факты вдруг обретают смысл. Такое случалось с каждым. Я знаком со многими преподавателями и лучшие из них умеют так преподносить урок, чтобы озарение у учеников возникало намного чаще.
В последние несколько лет я преподавал React всеми возможными методами. Все это время я делал подробные заметки о том, что провоцирует вот такие «Эврика!»-моменты.
Недавно я наткнулся на ветку Reddit, где обсуждалась та же идея. Обсуждение вдохновило меня написать эту статью, в которой я поделился основными инсайтами обучения. Надеюсь, она поможет вам по-новому взглянуть на принципы работы с React.
Что хорошо в React: то самое наитие, которое вы используете для JavaScript-функций, можно применять, чтобы понять, где и когда надо создать компоненты React. Отличие React вот в чем: вместо того чтобы брать некоторые аргументы и возвращать значение, ваша функция будет брать некоторые аргументы и возвращать объектное представление вашего пользовательского интерфейса (UI).
Эту мысль можно выразить формулой fn(d) = V. Читается так: «функция принимает некоторые данные и возвращает представление».
Это прекрасный способ представить себе разработку пользовательских интерфейсов — теперь ваш UI просто состоит из различных вызовов функций. Это похоже на создание приложений. Теперь вы можете использовать все преимущества композиции функций при создании пользовательских интерфейсов.
Наиболее распространенная реакция, которую я вижу у тех, кто впервые использует React, выглядит примерно так: «React — это круто, но вот JSX мне совсем не по душе. Он разрушает разделение ответственностей». JSX не пытается быть HTML. И он определенно больше, чем просто язык шаблонов. О JSX надо понять две важные вещи.
Во-первых, JSX — это абстракция над React.createElement — функцией, возвращающей объектное представление DOM.
Всякий раз при трансляции JSX у вас будет объект JavaScript, представляющий собой фактический DOM — или любой другое представление платформы, на которой вы находитесь (iOS, Android и т. д.). Затем React проанализирует этот объект и проанализирует фактический DOM. С помощью diff React может обновить DOM только там, где произошло изменение. Это повышает производительность, но, что более важно, показывает, что JSX на самом деле «просто JavaScript».
Во-вторых, именно из-за того, что JSX — это просто JavaScript, вы получаете все преимущества JavaScript: например, композицию, линтинг и отладку. Но вы также по-прежнему получаете декларативность и схожесть с HTML.
Когда вы впервые вникаете в React, вы учите, что «компоненты — это строительные блоки React. Они берут входные данные и возвращают некоторый интерфейс (шаблон дескриптора)».
Означает ли это, что каждый компонент должен напрямую возвращать дескрипторы пользовательского интерфейса, как мы обычно это изучаем? Что, если мы хотим, чтобы компонент отображал другой компонент (шаблон компонента более высокого порядка)? Что, если мы хотим, чтобы компонент управлял некоторой секцией состояния, а затем вместо возвращения дескриптора пользовательского интерфейса возвращал вызов функции в состоянии (шаблон Render Props)? А если бы у нас был компонент, который отвечает за управление звуком, а не за визуальный интерфейс, то что бы он возвратил?
В React хорошо то, что вам не нужно возвращать типичные «представления» из ваших компонентов. До тех пор, пока в результате возвращается элемент React, null или false, все хорошо.
Вы можете возвращать различные компоненты:
Компонентная архитектура, конечно же, усложняет разделение состояний. Если два компонента полагаются на одно и то же состояние, то где оно должно находиться? Это был такой популярный вопрос, что он спровоцировал появление целой экосистемы решений, и в итоге появился Redux.
Решение Redux заключается в помещении этого общего состояния в другое место, называемое «хранилищем». Компоненты могут подписаться на любые части хранилища, в которых они нуждаются, а также могут отправлять «действия» для обновления хранилища.
Решение React должно найти ближайший родительский элемент для обоих этих компонентов и заставить этого родителя управлять общим состоянием, передавая его дочерним компонентам по мере необходимости. У обоих подходов есть свои плюсы и минусы, но важно знать, что оба решения существуют.
К счастью, React всегда был очень свободомыслящим относительно принципов функционального программирования. Один из примеров перехода React от наследования к композиции — релиз 0.13, когда стало ясно, что React не добавлял поддержку Mixins с классами ES6.
Причина этого в том, что почти все, что можно сделать с помощью Mixins или наследования, вы также можете выполнить через композицию, но с меньшим количеством побочных эффектов. Если вы приходите в React с менталитетом наследования, то новый способ мышления может оказаться сложным и непривычным.
Если вы обратите внимание на строение компонента React, то он обычно включает в себя некоторое состояние, некоторые «крюки» жизненного цикла и разметку через JSX.
Что, если вместо размещения всего этого в одном компоненте, вы могли бы разделить состояние и крюки жизненного цикла от разметки? У вас получится два компонента. Первый будет содержать состояние, методы жизненного цикла и отвечать за то, как работает компонент. Второй будет получать данные через props и отвечать за то, как выглядит компонент.
Такой подход позволяет более эффективно повторно использовать ваши презентационные компоненты, поскольку они больше не связаны с данными, которые получают.
Я также обнаружил, что он позволяет и вам, и тем, кто будет вникать в ваш проект, лучше понять структуру приложения. Вы можете заменить реализацию компонента, не видя или не переживая о пользовательском интерфейсе, и наоборот. В результате разработчики могут настраивать пользовательский интерфейс, не беспокоясь, как презентационные компоненты получают данные.
Это еще одно преимущество отделения ваших презентационных компонентов от компонентов вашего контейнера. Состояние — товарищ несогласованности. Определив верные линии разделения, вы в значительно улучшите предсказуемость вашего приложения путем инкапсуляции сложности.
Спасибо, что нашли время прочесть мою статью!
Углубленное изучение JavaScript — это долгий путь. И библиотека React — лишь один из многих пунктов в резюме полноценного фронтенд-разработчика, при этом далеко не самый первый.
Если вы хотите к хорошим знаниям JavaScript добавить глубокое понимание Web API, научиться решать задачи на чистом JavaScript, вникнуть в BOM и DOM, изучить асинхронные HTTP-запросы (AJAX) и веб-сокеты (WebSocket) — записывайтесь на наш продвинутый курс «Front-end разработка: создаем интерактивные веб-страницы».
Одна из моих главных преподавательских задач — сделать так, чтобы у людей чаще случались моменты озарения. «Эврика!» — это момент внезапного прояснения, когда ранее непонятные факты вдруг обретают смысл. Такое случалось с каждым. Я знаком со многими преподавателями и лучшие из них умеют так преподносить урок, чтобы озарение у учеников возникало намного чаще.
В последние несколько лет я преподавал React всеми возможными методами. Все это время я делал подробные заметки о том, что провоцирует вот такие «Эврика!»-моменты.
Недавно я наткнулся на ветку Reddit, где обсуждалась та же идея. Обсуждение вдохновило меня написать эту статью, в которой я поделился основными инсайтами обучения. Надеюсь, она поможет вам по-новому взглянуть на принципы работы с React.
Озарение №1. Props для компонентов — то же, что и аргументы для функций
Что хорошо в React: то самое наитие, которое вы используете для JavaScript-функций, можно применять, чтобы понять, где и когда надо создать компоненты React. Отличие React вот в чем: вместо того чтобы брать некоторые аргументы и возвращать значение, ваша функция будет брать некоторые аргументы и возвращать объектное представление вашего пользовательского интерфейса (UI).
Эту мысль можно выразить формулой fn(d) = V. Читается так: «функция принимает некоторые данные и возвращает представление».
Это прекрасный способ представить себе разработку пользовательских интерфейсов — теперь ваш UI просто состоит из различных вызовов функций. Это похоже на создание приложений. Теперь вы можете использовать все преимущества композиции функций при создании пользовательских интерфейсов.
Озарение №2. В React пользовательский интерфейс вашего приложения полностью построен с использованием композиции функций. JSX — это абстракция над этими функциями
Наиболее распространенная реакция, которую я вижу у тех, кто впервые использует React, выглядит примерно так: «React — это круто, но вот JSX мне совсем не по душе. Он разрушает разделение ответственностей». JSX не пытается быть HTML. И он определенно больше, чем просто язык шаблонов. О JSX надо понять две важные вещи.
Во-первых, JSX — это абстракция над React.createElement — функцией, возвращающей объектное представление DOM.
Всякий раз при трансляции JSX у вас будет объект JavaScript, представляющий собой фактический DOM — или любой другое представление платформы, на которой вы находитесь (iOS, Android и т. д.). Затем React проанализирует этот объект и проанализирует фактический DOM. С помощью diff React может обновить DOM только там, где произошло изменение. Это повышает производительность, но, что более важно, показывает, что JSX на самом деле «просто JavaScript».
Во-вторых, именно из-за того, что JSX — это просто JavaScript, вы получаете все преимущества JavaScript: например, композицию, линтинг и отладку. Но вы также по-прежнему получаете декларативность и схожесть с HTML.
Озарение №3. Компоненты не обязательно должны соответствовать узлам DOM
Когда вы впервые вникаете в React, вы учите, что «компоненты — это строительные блоки React. Они берут входные данные и возвращают некоторый интерфейс (шаблон дескриптора)».
Означает ли это, что каждый компонент должен напрямую возвращать дескрипторы пользовательского интерфейса, как мы обычно это изучаем? Что, если мы хотим, чтобы компонент отображал другой компонент (шаблон компонента более высокого порядка)? Что, если мы хотим, чтобы компонент управлял некоторой секцией состояния, а затем вместо возвращения дескриптора пользовательского интерфейса возвращал вызов функции в состоянии (шаблон Render Props)? А если бы у нас был компонент, который отвечает за управление звуком, а не за визуальный интерфейс, то что бы он возвратил?
В React хорошо то, что вам не нужно возвращать типичные «представления» из ваших компонентов. До тех пор, пока в результате возвращается элемент React, null или false, все хорошо.
Вы можете возвращать различные компоненты:
render () {
return
}
You can return function invocations:
render () {
return this.props.children(this.someImportantState)
}
Or you can return nothing at all:
render () {
return null
}
Озарение №4. Когда двум компонентам необходимо разделить состояние, нужно его поднимать, а не синхронизировать
Компонентная архитектура, конечно же, усложняет разделение состояний. Если два компонента полагаются на одно и то же состояние, то где оно должно находиться? Это был такой популярный вопрос, что он спровоцировал появление целой экосистемы решений, и в итоге появился Redux.
Решение Redux заключается в помещении этого общего состояния в другое место, называемое «хранилищем». Компоненты могут подписаться на любые части хранилища, в которых они нуждаются, а также могут отправлять «действия» для обновления хранилища.
Решение React должно найти ближайший родительский элемент для обоих этих компонентов и заставить этого родителя управлять общим состоянием, передавая его дочерним компонентам по мере необходимости. У обоих подходов есть свои плюсы и минусы, но важно знать, что оба решения существуют.
Озарение №5. Наследование не нужно в React, а сдерживание и специализацию можно получить при помощи композиции
К счастью, React всегда был очень свободомыслящим относительно принципов функционального программирования. Один из примеров перехода React от наследования к композиции — релиз 0.13, когда стало ясно, что React не добавлял поддержку Mixins с классами ES6.
Причина этого в том, что почти все, что можно сделать с помощью Mixins или наследования, вы также можете выполнить через композицию, но с меньшим количеством побочных эффектов. Если вы приходите в React с менталитетом наследования, то новый способ мышления может оказаться сложным и непривычным.
Озарение №6. Разделение контейнерных и презентационных компонентов
Если вы обратите внимание на строение компонента React, то он обычно включает в себя некоторое состояние, некоторые «крюки» жизненного цикла и разметку через JSX.
Что, если вместо размещения всего этого в одном компоненте, вы могли бы разделить состояние и крюки жизненного цикла от разметки? У вас получится два компонента. Первый будет содержать состояние, методы жизненного цикла и отвечать за то, как работает компонент. Второй будет получать данные через props и отвечать за то, как выглядит компонент.
Такой подход позволяет более эффективно повторно использовать ваши презентационные компоненты, поскольку они больше не связаны с данными, которые получают.
Я также обнаружил, что он позволяет и вам, и тем, кто будет вникать в ваш проект, лучше понять структуру приложения. Вы можете заменить реализацию компонента, не видя или не переживая о пользовательском интерфейсе, и наоборот. В результате разработчики могут настраивать пользовательский интерфейс, не беспокоясь, как презентационные компоненты получают данные.
Озарение №7. Если вы пытаетесь сохранить большинство компонентов чистыми (pure), станет намного проще поддерживать элементы без состояния
Это еще одно преимущество отделения ваших презентационных компонентов от компонентов вашего контейнера. Состояние — товарищ несогласованности. Определив верные линии разделения, вы в значительно улучшите предсказуемость вашего приложения путем инкапсуляции сложности.
Спасибо, что нашли время прочесть мою статью!
От редакции
Углубленное изучение JavaScript — это долгий путь. И библиотека React — лишь один из многих пунктов в резюме полноценного фронтенд-разработчика, при этом далеко не самый первый.
Если вы хотите к хорошим знаниям JavaScript добавить глубокое понимание Web API, научиться решать задачи на чистом JavaScript, вникнуть в BOM и DOM, изучить асинхронные HTTP-запросы (AJAX) и веб-сокеты (WebSocket) — записывайтесь на наш продвинутый курс «Front-end разработка: создаем интерактивные веб-страницы».
Поделиться с друзьями
Fen1kz
Поставьте плашку перевода (Я писал в личку, ответа нет)
netologyru
Здравствуйте.Личку не успели посмотреть. Что вы имеете в виду под плашкой перевода? В лиде указано, что это перевод и дана ссылка на оригинальный текст.
maximw
На Хабре есть отдельный тип постов — «Перевод»
netologyru
Да, уже разобрались. Но после публикации ничего изменить нельзя. Поэтому в этот раз оставим как есть, в следующий раз уже сделаем все правильно. Простите!
Miraage
Эти озарения должны посещать сразу после внимательного чтения документации и просмотра двух курсов от Абрамова.
AlexAkhremenko
Достаточно даже просто внимательного чтения документации.
netologyru
К сожалению, так бывает, что люди чего-то не знают. Мы вот не знали о выпадающей плашке: или публикация, или перевод. После публикации уже не изменить. Поэтому признаем, что ошиблись. В следующий раз сделаем все правильно. Спасибо, что поправили!
raveclassic
Все хорошо, но не используйте слово «крюки».
chuikoffru
Жаль что примеры кода не приводились. «На слух» не всегда легко понять о чем речь.