misc/class
lib/jquery_pnotify, lib/moment, lib/lodash, misc/notification, site/engine, misc/social
if( $.browser.msie && $.browser.version <= 8 ) include('lib/respond'); $._social.__cfg = {"init":[{"service":"basic"},{"fb_app_id":"1997094873850041","service":"fb"},{"vk_app_id":"2978320","service":"vk"},{"service":"twi"}],"like":[{"service":"fb"},{"service":"vk"},{"via":"","channel":"","hash_tag":"","service":"twi"}]}; window._SiteEngine = new classes.SiteEngine( { user_id: 0, controller: 'content_tape', action: 'tag', content_css_version: '1459538664', social_enabled: 0} );

Faiwer

Блог web-программиста

Поиск по метке: JSX

React 16 & Context decorators

13 апреля 2018

С обновлением 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;
};

Забирайте кому надо ;)

JSX и вветвления ― jsx-control-statements

16 февраля 2017

Одна из раздражающих меня в React вещей, это помесь XML и JS синтаксиса. И ладно бы в одном файле, но, блин, даже в одном блоке. Сочетания XML и конструкций вроде {arr.map(arr => { очень сильно бьют, как по читаемости, так и по глазам в целом. К счастью, есть возможность этого избежать, используя jsx-control-statements. Т.к. его внедрение оказалось делом не совсем тривиальным, я решил написать об этому небольшой очерк.

Для начала, что нам даёт этот плагин?

<If condition={anyCondition}>...</If>
// вместо
{anyCondition && ...}

А также

<For each="el" index="key" of={arr}>...</For>
// вместо
{arr.map((el, key) => ...}

Т.е. XML-like конструкции, похожие на соответствующие им из XSLT (только более компактные). Также там есть ещё <Choice/> для switch-ей.

Ok, а как оно работает? Оно городит новые DOM-элементы? Нет. Оно ещё на уровне babel-я трансформируется в те самые && и .map. Т.е. это синтаксический сахар для эстетов. Ok, как подключить? 

  1. npm i jsx-control-statements
  2. в настройки babel-я в plugins добавляем "jsx-control-statements"

Всё, работает. А как насчёт lint-инга? Оказалось, что тут тоже всё схвачено (для eslint), но нужно немного понастраивать:

  1. npm i eslint-plugin-jsx-control-statements
  2. в настройках eslint
    1. в plugins добавляем jsx-control-statements
    2. в extends добавляем jsx-control-statements

Теперь никаких неудобств. Проблем с подстветкой синтаксиса тоже никаких (если у вас вообще JSX нормально отображается, конечно).