#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.

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