С обновлением React
до 16
версии мы получили новый вид контекста, на замену старому. Теперь это не мутное API
, как было раньше, а утверждённый вариант, с которым можно смело в бой. В чём же ключевые различия?
- Старый вариант был многословным. Новый вариант компактнее.
- Старый вариант не обновлял связанные с контекстом компоненты при изменении контекста. По сути контекст должен был быть имутабельным. Новый вариант обновляет связанные с ним компоненты.
- Старый вариант можно было использовать в
любом
методе компонента. Новый только вrender
-е. - Старый вариант не имел пенальти по производительности и не требовал использования
HOC
-ов, не увеличивал иерархию древа. Новый вариант всё это делает. Скажем дляconnect
-а изredux
-а потребуется аж 2 дополнительных уровня иерархии. - Старый вариант был оформлен в виде
static полей класса
, новый вариант в видеfunction as tag content
. И то и другое слегка уродливо. Или не слегка. JSX в целом страшненький. А тут…
В итоге послевкусие специфическое. С одной стороны API хотя бы устаканили. С другой стороны сделали его каким-то очень неудобным и вообще кривоватым. Такое впечатление возникает в целом, глядя на новые возможности из 16+. Но тут я остановлюсь на работе с контекстом.
Писать вот так:
render() { return <Consumer>{arg1 => <Consumer2>{arg2 => <div>/* some code with them */</div> }</Consumer2> }</Consumer> }
… невыносимо. Хочется удобства. В итоге это вылилось в такой вариант:
@renderContext('arg1', 'arg2') render(arg1, arg2) { return <div>/* some code with them */</div>; }
По сути я воспользовался декораторами из ES7
, которые пока под некоторым вопросом. Но т.к. JSX
в стандарте тоже нет, то плевать. Что делает данный декоратор? Он оборачивает метод render
обёртками из кода выше. Но делает это автоматически. А в исходный render метод передаёт все контексты как аргументы функции в том же порядке.
Никакой магии в этом нет и все эти обёртки над обёртками никуда не испарились, но теперь хотя бы скрыты с глаз долой. Помимо прочего я написал ещё несколько декораторов. Один для <Provider/>
-ов, один для HOC
, один для удобтва i18n
. Чувствую в декораторы затянет меня с головой. Ух злая эта штука. Это не к добру :)
Сам декоратор устроен вот так:
const renderContext = (...keys) => function(target, methodName, descriptor) { const render = descriptor.value; descriptor.value = keys .map(key => list[key].Consumer) .reverse() .reduce((inner, Consumer) => { return function(...args) { return <Consumer> {arg => inner.call(this, ...args, arg)} </Consumer>; }; }, render); return descriptor; };
Забирайте кому надо ;)