#9 React - функциональные компоненты

poster
В этом уроке мы с вами рассмотрим как создавать компоненты в React не с помощью классов, а с помощью чистых функций без состояния.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

В этом уроке мы с вами рассмотрим как создавать компоненты в React не с помощью классов, а с помощью функций.

Итак в React 0.14 был введен новый способ определения компонентов. С помощью чистых функций. Какие же плюсы есть у этого подхода и почему н устроили классы?

  1. Функции проще, вам не нужно создавать класс, использовать extends и конструктор. Основная проблема была в том, что многие люди использовали классы неправильно. С чистыми функциями сложнее написать плохой код
  2. У вас нет необходимости использовать контект. То есть не нужно биндить this, чтобы он был правильный и код выходит чище
  3. С помощью чистых функций создаются компоненты без внутреннего состояния. И у вас никогда не будет возможности выбрать хотите ли вы хранить данные в локальном стейте или в нормальном сторе. Вы просто не сможете по лени или незнанию использовать локальный стейт, а значит все ваши данные вы вынуждены будете хранить нормально.
  4. Описание компонентов с помощью чистых функций создает меньше кода, а значит его легче поддерживать.
  5. Чистые функции намного проще тестировать. Вы просто передаете props на вход и ожидаете какую то разметку.
  6. В будущем чистые функции будут выигрывать по скорости работы в сравнении с классами из-за отсутствия методов жизненного цикла

Ну давайте наконец то попробуем

Возьмем App.js, который мы писали для треков и попробуем переписать на чистые функции.

Уберем импорт компоненты из react.

import React from 'react';

и заменим класс на функцию

const App = (props) =>

То есть сейчас у нас обычная функция App, которая принимает на вход props. Для того, чтобы не писать лишний код мы можем делать деструктуризацию сразу при прокидывании данных

const App = ({ tracks }) =>

Вместо метода render оставим только return в этой функции.

return (
  <div>
    <Menu/>
    <div>
      <input type="text" ref={(input) => { trackInput = input }} />
      <button onClick={addTrack.bind(this)}>Add track</button>
    </div>
    <div>
      <input type="text" ref={(input) => { searchInput = input }} />
      <button onClick={findTrack.bind(this)}>Find track</button>
    </div>
    <div>
      <button onClick={onGetTracks}>Get tracks</button>
    </div>
    <ul>
      {tracks.map((track, index) =>
        <li key={index}>{track.name}</li>
      )}
    </ul>
  </div>
);

Изменим методы класса на обычные функции и уберем везде this. Создадим локальные переменные trackInput и searchInput. Добавим в деструктуризацию все екшены, которые мы используем

let trackInput = '';
let searchInput = '';

const addTrack = () => {
  console.log('addTrack', trackInput.value);
  onAddTrack(trackInput.value);
  trackInput.value = '';
}

const findTrack = () => {
  console.log('findTrack', searchInput.value);
  onFindTrack(searchInput.value);
}

Как мы видим, после всех наших изменений код по прежнему работает. Теперь у нас вместо класса функция с параметрами, нет this, что упрощает работу, connect нам вообще не пришлось менять. Такой компонент намного проще тестировать. Нужно только помнить, что локальный стейт мы уже использовать не можем и нам нужно абсолютно все данные хранить в store.

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Олександр Матковський
6 лет назад
Нету ссылки на следующий десятый урок (https://monsterlessons.com/project/lessons/react-pishem-css-v-javascript)
monsterlessons
6 лет назад
Ее нет, так как урок "Пишем css в javascript" не относится к серии "React для начинающих", по моему мнению.
talnax
6 лет назад
Большое спасибо, за объяснения и рекомендации
monsterlessons
6 лет назад
На здоровье)
talnax
6 лет назад
Доброго Вам дня. Возник вопрос, попытался найти ответ в уроках, но видимо плохо искал. Линк: https://proglib.io/p/react-js-interview/ Вопрос: 6. Как бы выглядел приведенный ниже элемент Twitter в React? render () { return this.props.children(this.state.user) } Так, что же это за зверь такой props.children, мы его в компонент не передавали ! Может информация есть в каком то другом уроке(курсе) ?
monsterlessons
6 лет назад
Добрый день. На самом деле все очень просто. У любого компонента всегда есть this.props.children. Это содержимое компонента при его вызове. <SomeComponent>Hi. I'm props</SomeComponent> Соотвественно то, что написано между открытием и закрытием компонента - это всегда children. Кстати код из примера №3 супер плохой и я бы не советовал так писать, потому что тут попахивает отсутствием здравого смысла. В нормальном приложении у нас есть 2 тупых компоненты без состояния: Loading и Twitter. И у нас должна быть родительская компонента с фетчем, где проверяется какую компоненту надо рендерить.
Дмитрий Леонтьев
6 лет назад
Привет, а будет возможность рассмотреть работу с immutable-js на примере React/Redux?
monsterlessons
6 лет назад
Привет, спасибо за предложение, добавил в список будущих видео.
yarovoy
6 лет назад
Здравствуйте! Подскажите пожалуйста, разрабатывая приложение локально с использованием реакт роутера 4 версии все ок, для теста хотелось попробовать положить его на хостинг и посмотреть корректность работы, и возникла проблема с роутером, перейдя на какую-то страничку например domain-name/page-name нажав кнопочку обновить страничку получаю сообщение такого рода Not Found The requested URL /page-name was not found on this server. Может быть у вас есть рекомендации по поводу того, что нужно сделать для того чтобы была корректная работа роутера, спасибо!
monsterlessons
6 лет назад
Добрый день. Ваш сервер должен на любой запрос всегда отрисовывать вашу html страницу с js. Тогда реакт сможет применить свой роутер. На данный момент у вас проблема не в клиенте, а в сервере.
yarovoy
6 лет назад
Спасибо!
Михаил Кондрашкин
7 лет назад
А как лучше повесить событие к примеру componentWillMount или componentWillUpdate на функциональный компонент? Например, при переключении страниц через route производить обновление содержимого
monsterlessons
7 лет назад
Если вы используете react-router, то вы просто на каждый роут вешаете свой компонент. И даже если они stateless, они будут перерисовываться автоматически. stateless компоненты не имеют lifecycle. Они просто перерендериваются при изменении props.
Михаил Кондрашкин
7 лет назад
Да, я как раз использую react-router и react-router-redux. Не могу понять, как перехватить event - @@router/LOCATION_CHANGE и выполнить конкретное действие для определенного компонента. Жизненный пример - я хочу обработать вызов route Claims, сделать fetch к серверу и отобразить свежие данные
monsterlessons
7 лет назад
Вот пример роутера. Каждый раз, когда вы переходите на страницу /posts у вас вызывается fetchPosts и когда данные получены, мы меняем state. Соотвественно в рендере отрисовываете данные из this.state. ReactDOM.render( <Route component={Layout}> <Route path='/posts' component={Posts} /> <Route path='/contacts' component={Contacts} /> </Route> , document.getElementById('root') ); class Posts extends Component { componentDidMount () { fetchPosts.then(data => this.setState({posts: data})) } render () { ... } }
Михаил Кондрашкин
7 лет назад
Ну да, все правильно, так сейчас и работает. Но если переделать на функциональный компонент (убрать class extends Component и render) то нет возможности добавить componentDidMount. Или так нельзя сделать через функциональный компонент?
monsterlessons
7 лет назад
Так нельзя сделать через функциональный компонент. Вы можете сделать класс, как враппер вокруг вашего stateless компонента, который будет отвечать только за получение данных и передавать все данные с помощью props в дочерний компонент. Не нужно прям везде пытаться переписать на stateless. Где нужен lifecycle, спокойно используйте class.
Михаил Кондрашкин
7 лет назад
Понятно, спасибо. У вас очень полезный ресурс, объясняется все очень хорошо!
monsterlessons
7 лет назад
Спасибо. Стараюсь.
OmniWeb
7 лет назад
Функциональный подход крут) То есть, если я хочу строить архитектуру приложения именно таким способом, то для работы с динамическими данными (клиентскими и из БД), мне обязательно понадобится Redux?
monsterlessons
7 лет назад
Не обязательно, но Redux - это хорошее решение для хранения состояния приложения и взаимодействия с API.