Comments 26
Про key
забыли.
<ul>
{["first", "second"].map((item) => (
<li>{item}</li>
))}
</ul>
<ul>
{[
<li>first</li>,
<li>second</li>,
]}
</ul>
Будет предупреждение:
Warning: Each child in an array or iterator should have a unique "key" prop. See https://fb.me/react-warning-keys for more information.
const {id: someIdInData} = data
console.log(id)
Но вроде бы обещают сделать.
Что происходит, когда надо перерисовать компонент? Вызывается метод shouldComponentUpdate(nextProps, nextState): Boolean.
Если метод вернет false, то всё дерево компонентов, которое строится в результате работы метода render() останется нетронутым — это называется short circuit. Т.е. ты как-бы говоришь реактовскому движку «спокойно парень, я уверен, ничего не изменилось», и реакт пропускает целиком все поддерево, которое растет из этого компонента.
Если метод вернет true, то реактовский движок вызовет метод render, сверит результат и если что-то изменилось, то начнется reconciliation, который сам по себе отдельная история.
Мораль: правильно написанный (но не всегда :) ), shouldComponentUpdate может сильно ускорить перерисовку.
И вот этого метода в functional components нету, хотя было бы круто, если бы был.
Лучше всего управлять потомками при помощи специальных методов — React.Children. Например пример ниже позволяет вернуть только потомков и не требует дополнительной обертки
return React.Children.only(this.props.children)
Это лишь способ указать, что children железно должен быть одним элементом в любом случае. Иначе React бросит исключение. Это никак не возможность вернуть несколько дочерних элементов напрямую, без оборачивающего элемента. Пример выше лишь проверит, что потомок один и вернет его.
В статье с названием "паттерны React" всего один паттерн (stateless component) и один антипаттерн (event switch), ну за уши можно притянуть еще и "Higher-order component", что, вообще-то говоря, некое подобие карринга, а, главное, является основами JS в секции "замыкания". Остальное — либо непонимание ООП (Container component), хотя, в целом, это ближе к паттерну "провайдер" (https://en.wikipedia.org/wiki/Provider_model), либо возможности es2015+ или jsx.
Теперь конструктивно по пунктам:
Про stateless function, она же "глупый компонент", "глупое представление" и "чистая функция" (в очень вольной интерпретации) сказано про её красоту, но не сказано главное преимущество, ведь действительно, всем плевать на производительность, когда можно писать так, в пару строк, без всяких там классов. А именно — у нее есть автоматический shouldComponentUpdate, который всегда сверяет — изменились ли переданные параметры или нет, что делает использование этого синтаксиса крайне желательным и удобным, покуда позволяет повысить производительность без лишних строк кода (проверки параметров вручную), но накладывает ограничение — параметры сверяются через ===, т.е. если изменилось какое-то свойство объекта, а не сам объект (объект передался по ссылки по-прежнему), компонент не перерисуется, будете гадать потом почему. Хорошо работает в купе с immutable.
JSX Spread Attributes. Object.assign для ленивых, но нужно признаться, что очень удобный функционал. Более того, он так же работает и в js, так что можно писать что-то в стиле
const options = {someDefaultValue: true, anotherValue: false, ...passedOptions};
. Только не забываем подключить preset: react в babel.
Conditional Rendering. Зло, best practices — выносить подобные вещи в константы и определять их до функции return. Например:
const warningMsg = hasWarning && <div>warning: {warning}</div>; return (<div> {warningMsg} </div>);
Ну и да. ЧЕГО? Какой conditional renderig? Тут просто стандартные возможности js (еще в далеком 2007 писали
var something = param.something || default
) + основы JSX в виде рендера того, что находится в фигурных скобках.
Children Types. Ложь, кроме как строки, Number, Boolean и React node, а так же массива из этого, (с недавних, вроде как с 0.14 версии, еще и null) ничего он рендерить не умеет. На попытку отрендерить обычный объект ругнется Error: Objects are not valid as a React child. Вдобавок, это эм документированная (но автор документацию явно не читал) и основная, как шаблонизатора, возможность JXS, давайте как паттерны может быть еще и то, что в JS можно два числа складывать напишем?
Children pass-through. Опять же есть в документации и является частью библиотеки. Однако будте предельно осторожны с этой функцией, можно напороться, что он по той или иной причине не перерендерит.
Event switch. Антипаттерн, имеющий целый вагон проблем. Одна из основных — IDE вам тут никак не поможет, а вместо ENUM или хотя бы констант используются строки, шанс ошибиться велик. Вторая — масштабируемость и расширяемость. Вообще задание "перепишите код с switch таким образом, чтобы его было легко изменять и расширять" — типичное тестовое задание для junior, что как бы намекает, что так лучше не делать. Ну и да, полностью ломает ООП, че уж.
Layout component. Используйте в нем shouldComponentUpdate с умом и крайней осторожностью, потому что если вы захотите передавать сквозь него какие-то параметры в дочерние элементы из "умного компонента" вниз в "глупые", то из-за принудительного false в shouldComponentUpdate ничего перерисовываться не будет.
- Higher-order component: я уже говорил, что это карринг, а так же основы js, не понятно, по какой причине они бы не срабатывали в JSX.
Это были замечания к автору. Замечания к переводчику: promt образца 2007 года detected. Каждое второе предложение переведено настолько странно, что если кидать в личку — исправлений наберется на вторую такую же статью.
Однако, как ни странно, статья неплохая и в ней много полезного, осталось это привести к человеческому виду.
Дико извиняюсь. По первому пункту я телепортировался в будущее, когда это уже сделали. Пока что ничего такого нет, но в документации слезно клянутся, что будет, и что этот синтаксис стоит использовать всегда, когда есть возможность, и в какой-то чудесный момент ваше приложение резко прибавит в скорости (хороший ответ на stackoverflow )
Насчёт 7. switch
в javascript зло конечно дикое, но из него можно изобразить что-то вроде паттерн матчинга для бедных. Для очень бедных.
switch(true) {
case type === "click" && something.isDefined() === true:
return "It was click";
case type === "mouseenter" && somethingElse.isDefined() === true:
return "It was mouseenter";
default:
return console.warn(`No case for event type "${type}"`);
На мой взгляд даже в таком виде это сильно симпатичнее цепочки if-else-if
. Но дно достигается, конечно, в момент объявления переменной в любом case
. Никакие let
и const
не спасают — scope у всех один.
case type === "click": {
...
return;
}
Я вот либо что-то упустил в самых основах, либо это нечто совсем недавно появилось. Но хм… это не создает новой области видимости. Если не сложно, можно ссылку на пример? Вот gist с прямым примером: https://gist.github.com/wertlex/b97115e0f2fe0bc023297f6b2db8edd5
В теории, если я не ошибаюсь, должна создаваться блочная область видимости. Как браузеры делают — не знаю. Babel просто имитирует блочную видимость и в вашем примере переименует второй value в _value, чтобы имена не пересекались.
Это, кстати, recommended-practice небезызвестного Redux'a хоть и для иных строк.
допустим там у дива класс появился, у ворнинга свое условие и эвент еще какой?
Если это класс и подобное — нет, имеется ввиду наличие или отсутствие или выбор одного из двух элементов. Классы и прочие аттрибуты — тоже желательно считать до рендера, но местами, чтобы не загромождать, можно и инлайново. Если же весь шаблон сделать вот как рекомендует автор (инлайново в шаблоне) — он быстро разрастется и станет нечитаемым. Что касается когда нужно выносить в константу, а когда в отдельный компонент — по мне, так первым сигналом является переиспользование. Если испольуете одно и то же хотя бы в двух местах — уже выносите. Если просто говорить про объем — я не могу сказать какое-то конкретное количество строк, на усмотрение ваше
Остальное пожалуй больше для начинающих, кто в 2007 про var something = param.something || default ничего знал.
JSX Spread Attributes имеет одну проблему, в дочерний компонент может залететь то, что не нужно. И начиная с 15 версии Реакт начинает ругаться на атрибуты, которые не были указаны в PropTypes
Паттерны React