С обновлением 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; };
Забирайте кому надо ;)