Как стать автором
Обновить

Комментарии 44

Там веселее было — в тексте упоминал разные теги, такие как <div> <App> <kbd> — они в итоге не показались, но съели закрывающий </b> — в итоге пришлось выискивать такие места и заменять < и > на соответствующие escape-последовательности)

Теперь исправил, вроде теперь всё корректно отображается :)
Начать с React и Bootstrap за 2 дня
Вот за это большое спасибо — почитаем!

На этой неделе планирую 2ю часть опубликовать, где будет больше про Bootstrap, которого в 1й части лишт слегка коснулся.

А без bootstrap-a никак все это не выровнять и размер шрифта не установить?
Да всё можно и без Bootstrap. Просто с Bootstrap это удобнее и красивее:)
Кому удобней? Пользователю, которому придется скачивать дополнительный код, размером больший, чем все остальное, и грузить свой браузер парсингом полутора тысяч ненужных ему css правил?

Программисту для удобства разработки. Пользователю для удобства работы. Пользователи в отличие от программистов устроены так, что им важно, чтобы было красиво и приятно глазу и они не задумываются о производительности. Например, я часио наблюдаю, как у людей пользователей одновременно запущено более 10 приложений и открыто более 100 сайтов. Хотя в целях производительности надо было сократить их в идеале до 1, или хотя бы до 3-4.


Не отрицаю, что приведённый код можно (а для высоконагруженных приложений) нужно оптимизировать — про оптимизацию есть куча статей. Да то же кэширование может помочь. Статья не про это. А про то, как быстро узнать, что это за технология такая React, и можно ли сделать красиво с помощью Bootstrap?

У пользователя ваш bootstrap и вытягиваемый им jquery отъедят лишние несколько мегабайт/десятков мегабайт с окна браузера и загрузят процессор. От всех пользователей говорю вам за это большое спасибо. За то, что вместо десятка простых css правил вы подключаете огромный css/js фреймворк, просто потому, что вам так удобно. Сразу же уча таких же как вы начинающих веб-девелоперов не мелочиться.

Предлагаю решать проблемы по мере их поступления. У меня была задача за пару дней изучить React и сделать на его базе красивое Web-прмложение. В постановке задачи

В постановке задачи не было про производительность.


Если потребуется оптимизировать производительность — это уже отдельная задача. Возможно в этой задаче откажемся от Bootstrap, а может даже и от React. Может вообще о кажемся от сайта и будем делать нативное мобильное приложение с кусками кода на ассемблере)))

Внёс уточнение в начало статьи, чтобы не вводить людей в заблуждение.
НЛО прилетело и опубликовало эту надпись здесь
вообще да, если открыть документацию бутстрапа это можно увидеть

Зачем вам js-часть бутстрапа? Она же будет конфликтовать с React! При желании, конечно же, их можно подружить — но это требует куда более вдувчивого подхода к программированию чем тут продемонстрирован.

А можно подробнее? Где именно будет конфликтовать? Я лишь описываю свой первый опыт изучения React с Bootstrap и описать его максимально простыми словами, без глубокого погружения в ООП, производительность и т.д. И что понимаете под более вдумчивым подходом к программированию? Если что, в следующей статье планирую разобрать код на отдельные файлы-компоненты, добавить unit-тесты.

Ну вот, например, решили вы сделать через бутстрап Collapse. И пишете:


<>
  <a className="btn btn-primary" data-toggle="collapse" href="#collapseExample" >Show/Hide</a>
  <div className="collapse" id="collapseExample">
     {this.props.text}
  </div>
</>

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

Спасибо за уточнение. Как лучше переписать такой код?

Если анимации необязательны — то вот так:


<>
  <a className="btn btn-primary" onClick={this.toggle}>Show/Hide</a>
  <div className={this.state.show ? 'collapse show' : 'collapse'}>
     {this.props.text}
  </div>
</>

Если анимации нужны — то нужно либо искать готовое решение именно для React, либо начать с чего-то похожего на вот этот код (и быть готовым фиксить его баги):


class Collapse extends React.PureComponent {
    render() {
        return <div>{this.props.children}</div>
    }

    componentDidMount() {
        const $this = $(ReactDOM.findDOMNode(this));
        $this.css({ collapse: true, show: this.props.visible });
    }

    componentDidUpdate(prevProps) {
        const $this = $(ReactDOM.findDOMNode(this));
        if (this.props.visible && !prevProps.visible)
            $this.collapse('show');
        else if (!this.props.visible && prevProps.visible)
            $this.collapse('hide');
    }

    componentWillUnmount() {
        const $this = $(ReactDOM.findDOMNode(this));
        $this.collapse('dispose');
    }
}

// ...

<>
  <a className="btn btn-primary" onClick={this.toggle}>Show/Hide</a>
  <Collapse visible={this.state.visible}>
     {this.props.text}
  </Collapse>
</>

Точнее не скажу, потому что я React за пределами песочницы ни разу не использовал.


Кстати, именно из-за сложности последнего решения я и говорю, что js-часть бутстрапа начинающим лучше совместно с React не использовать: нужно понимать что этот код вообще делает, и быть готовым написать аналогичную обертку для любого бутстрап-компонента.

Благодарю. Как буду за компьютером попробую и обновлю статью.

Пересмотрел я код в статье, но так и не нашёл, использования Collapse и id. На будущее приму к сведению. Кстати, JS-часть Bootstrap отключил (обновил статью)
Ну разумеется вы его там не нашли! :-) Претензия-то была к js-части бутстрапа, которую вы подключили, но не использовали. Проблема была в самом факте подключения.

js-часть Bootstrap уже отключил, что и отметил в статье:)

Вот этим меня бутстрап и не устраивает — то, что для него нужен jquery, что при наличии реактивного фреймворка как бы немного глупо. В этом плане больше bulma нравится.
Про bulma не слышал, посмотрю. Сейчас самый распиаренный именно Bootstrap, и в вакансиях именно он указывается — поэтому его и взял.

А по поводу jQuery пока в официальной документации обнаружил, что jQuery нужен только для JS-части Bootstrap. Сейчас думаю, как выпилить JS из Bootstrap и оставить только CSS от Bootstrap.
Можно попробовать использовать React bootstrap . При беглом просмотре я не нашел в зависимостях пакета JQuery.
Посмотрел React bootstrap — он основан на Bootstrap 3 и всё ещё находится в статусе беты (судя по номеру релиза). Мне хотелось изучить именно Bootstrap 4, где сетка реализована на FloatBox, а в следующей статье я как раз планирую активно использовать эту сетку. А так да, React bootstrap — интересный вариант для оптимизации.
Только сейчас заметил, что написал FloatBox. Конечно-же имел ввиду FlexBox.
> this.stopTimer = this.stopTimer.bind(this);
> this.resetTimer = this.resetTimer.bind(this);

Чтобы таким не заниматься, можно определять методы как стрелочные функции

class MyComponent extends PureComponent {
  state = {
    stopped: false,
  };

  stopTimer = () => this.setState({ stopped: true });

  render() {
    return (
      <button onClick={this.stopTimer}>Астанавитесь!</button>
    );
  }
}


> для этого добавим установку document.title в метод render():

Какой ужас :)

Здесь лучше подойдёт componentDidUpdate, потому что рендер может вызываться бесчисленное количество раз в зависимости от различных условий и всё, что он должен делать — возвращать новый VDom, за счёт чего «лишний» рендер будет менее дорогим.
Благодарю, попробую заменить стрелочной функцией и перенести определение заголовка в componentDidUpdate. Если всё успешно получится — внесу коррективы в этот пост.
Но тут важно помнить, что стрелочные функции не дружат с наследованием.
Честно говоря, не могу придумать ни одного кейса, когда в Реакте необходимо наследование, кроме наследования от Component/PureComponent.
Тем не менее, в Реакте допустимо наследование — а значит, кто-то будет им пользоваться.
Цитата из learn-reactjs.ru/basics/composition-vs-inheritance:
«В Facebook React используется в тысячах компонентов, но не было обнаружено каких-либо ситуаций, где разработчики рекомендовали бы создавать иерархии наследования компонентов.»
Композиция хорошо работает с готовыми компонентами. А для полуфабрикатов с кучей точек расширения альтернатива только хоки (HOC), но от тех все уже так устали, что придумали хуки.
1.Добавил в статью вариант с использованием стрелочной функции для обработки событий
2.Перенёс установку заголовка в componentDidUpdate()

Нашел у вас в коде вот такую строчку:


this.setState({value: this.state.value + 1})

Здесь вы неявно предполагаете, что между вызовами setState состояние успеет обновиться.
Так делать опасно: если на странице будет происходить что-нибудь "тяжелое", то ваш таймер начнет пропускать секунды. Казалось бы, это маловероятно, целая секунда же в периоде… Вот только тот сайт, где вы это читаете, умудряется тормозить на страницах с кучей комментариев даже без скриптов, на чистом css.


Рекомендуемый документацией React вариант выглядит вот так:


this.setState(state => ({ value: state.value+1 }));

Благодарю, подправлю

ИМХО, в 2к18 bootstrap не нужен. Тем более с reactJS. Пишем на реакте и тащим jQuery как зависимость(bootstrap), а смысл в этом какой? Хотите красоту? Ну возьмите современный UI-kit, вроде того же blueprintJS

Не стоит учить «плохому»
Ваше желание поделиться новыми для Вас знаниями можно понять, но почему хабр? Не достаточно ли было показать это своим друзьям или выложить на каком-нибудь форуме? Мало того, что статья на уровне «объясню как понял» (с примером из документации), так еще и код в ней, как говорится, с душком — учить такому совершенно не стоит торопиться:
Для начала нам нужен менеджер пакетов. Я выбрал npm, а он есть в Node.js
На самом деле для запуска Вам нужен Node.js, а без менеджера пакетов даже можно обойтись. Но судя по статье — нода, это просто что-то, где есть npm.
this – текущий класс
this не текущий класс, а контекст. В Вашем случае — экземпляр класса.
Далее стандартная обработка конструктора родительского класса super(props)
Конструктор не обрабатывается, а вызывается.

Ну и по коду.
const INTERVAL = 100;
На самом деле это не интервал, интервал в Вашем случае — 1000/INTERVAL (в описании Вы и сами пишете, что это частота).
this.stopTimer = this.stopTimer.bind(this);
В комментариях уже упоминались стрелочные функции и proposal class properties.
this.setState({value: this.state.value + 1})
Также в комментариях уже упоминалось о возможности асинхронного обновления состояния, в связи с чем оф. документация рекомендует использовать использовать функциональный стиль.
stopTimer(){
	this.setState({stopped: !this.state.stopped});
		if(this.state.stopped){
			clearInterval(this.timerID);
		}
		else
		{
			this.timerID = setInterval(() => this.increment(), 1000/INTERVAL);
		};
	}
}
Судя по названию метод должен останавливать таймер, но он его и запускает. Не должен ли он тогда называться toggleTimer()?
this.timerID = setInterval(() => this.increment(), 1000/INTERVAL);
и
clearInterval(this.timerID);
Повторяющийся код в данном случае можно вынести в отдельную функцию.
if (this.state.stopped) document.title = "Таймер";
Вы выносите в отдельную переменную value, но не stopped. Подобные обращения на несколько уровней вложенности тяжело читать. Сделать код читабельнее и короче Вам поможет деструктуризация.
Math.floor(value/INTERVAL/60/60)+":"+Math.floor(value/INTERVAL/60) % 60+":"+Math.floor(value/INTERVAL) % 60;
Подобные выражения лучше предварительно вычислять и сохранять в соответствующие переменные, тем более что их значения по коду используются несколько раз (для отображения в заголовке окна и в самом таймере).
{value % INTERVAL < 10 ? '0' : ''}{value % INTERVAL}
Для добавления ведущих нулей обычно используется padStart(), преимущества которого особенно заметны в тех случаях, когда ведущих нулей больше одного. Интересно, что ведущие нули есть только у децисекунд. Если Вам было лень дублировать ту же логику для секунд/минут/и т.д. могли бы выделить ее в отдельную функцию.
Также надо исправить метод increment(), чтобы он останавливался, когда stopped = true:
Разве не для этого был остановлен таймер?
<div class="container-fluid align-items-center">
Оф. документация любезно просит использовать className вместо class, о чем React сигнализирует в консоли разработчика своими warning'ами.
&nbsp;
Совместно с flexbox'ом выглядит очень прогрессивно =)

Даже после исправления всех этих упрощений и ошибок (в т.ч. орфографических) статья все еще не сможет называться «Изучаем реакт», скорее «Изучаем еще один способ сделать таймер с применением реакта». Пожалуйста, не торопитесь делиться тем, в чем еще сами не до конца разобрались, тем более на ресурсе такого уровня. Подобных статей на хабре итак много, что превращает его в помойку из выброшенных велосипедов.

Для тех же, кому действительно хотелось бы изучить реакт за один день, могу посоветовать данный материал, в котором все по порядку объясняется на доступном языке и наглядном примере (есть продолжения про redux и router). И да, дня вполне хватит, чтобы его прочитать и попрактиковаться. повторив все действия автора.

Благодарю за комментарии и подробные предложения по редактуре. Как буду немного посвободней - внесу предложенные изменения в статью.

Статья писалась для начинающих, для тех, кто ни разу не пробовал React и хотел бы разобраться с ним. Да, за основу я взял официальную документацию, но там многие моменты не были расписаны или наоборот было много воды. Хотелось сжать информацию, чтобы с основами можно было ознакомиться за 10 минут, а не за день (сколько мне потребовалось на изучение документации).

То что статья кажется слабой для мидлов и синьоров - возможно. Но она писалась не для них, а для трейни и джунов, которым интересно попробовать React и решить хотят они дальше его изучать или нет.

И спасибо за ссылку - почитал, там действительно всё подробно описано.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации