User avatar

Короче, ломовой инсайт! Lifecycle реактовского компонента на самом деле состоит из двух таймлайнов, ортогональных в смысле пространства Минковского. Первый таймлайн — это то, где живет рендеринг, this.props, this.state, this.context. Он tick-based, внутри него время в хорошем смысле не течет, потому что он в норме чисто функциональный. Назовем его рендерным.

Comment

2/ Второй таймлайн — это цикл жизни нижележащего JS-класса (наследника React.Component). В него входят this, DOM, promises разного вида и прочее. Назовем его императивным.

 ‎· псы в рапиде
Comment

3/ Границы между таймлайнами в идеале должно статически проверяться компилятором, но на практике в силу особенностей языка этого не происходит, поэтому все держится на guidelines/best practices. Новые значения this.props приходят вообще снаружи, от вызовов ReactDOM.render(). Новые значения this.state приходят только из императивного таймлайна. В идеале компилятор должен внутри функций, реализующих рендерный таймлайн давать доступ только на this.state и this.props, причем только константный. Внутри функций, реализующих императивный таймлайн, должен быть свободный доступ ко всему, кроме this.props (только на чтение) и this.state (только через this.setState()).

 ‎· псы в рапиде
Comment

4/ Смешная штука — на самом деле есть единственный способ передать сигнал из рендерного таймлайна в императивный — через componentDidMount(), внутри которого можно делать все что угодно, но только один раз сразу после конструирования JS-объекта.

 ‎· псы в рапиде
Comment

5/ На самом деле функция ReactDOM.render() делает UPSERT! Это ключевая инсайт-лемма.

 ‎· псы в рапиде 1
Comment

6/ Зачем нужно передавать сигнал из рендерного таймлайна в императивный? Зайдите на морду мокума, нажмите на Add music — у вас откроется textarea для ввода HTML-кода, которая будет сфокусирована. Как этого добиться? Ведь у нас нет прямого контроля над тем, когда она создастся и появится тот самый ref, на котором можно сделать .focus(). Ответ — мы делаем это внутри componentDidMount(), конечно. 90% задач укладываются в это. В моей личной практике я пока не смог придумать, где может понадобиться что-то сложнее, но зато я уже придумал как это сделать.

 ‎· псы в рапиде 2
Comment

7/ чтобы передавать произвольные сигналы из императивного таймлайна в другой императивный таймлайн с гарантией прохода через рендерный барьер, мы можем использовать массивы длины единица с изменяющимися key. При смене ключа будет создан новый компонент, а значит он сможет что-то еще сделать.

 ‎· псы в рапиде 2
Comment

Короче, это охуенно!

 ‎· псы в рапиде 3
Comment

4-bis/ я конечно ошибся, есть еще componentDidUpdate(prevProps, prevState), но тут зависит от того как именно будет устроен сигнал. Так как он может быть только edge-triggered, и при этом все ближе тот день, когда процесс рендеринга будет отцеплен от ReactDOM.render(), то нужно будет аккуратно обрабатывать эту "лесенку" переходов.

 ‎· псы в рапиде
Comment

8/ Вообще то что я называю рендерным и императивным, кажется, на самом деле совершенно чисто разделено в классах React и ReactDOM (а также реализациях для других сред, типа react-native).

 ‎· псы в рапиде
Comment

9/ власти скрывают от нас еще один момент: на самом деле, внутри this.props могут храниться не только данные, но и функции. Это означает, что можно в componentDidMount вызывать this.props.callback(), тем самым достигая нирваны, практически ReactDOM.render(...).then(() => { ... });

 ‎· псы в рапиде 1

1 2 3 4 5 6 7 8 9 10