Новый способ заставить небольшие программы поддерживать синтаксис JSX

React.js

ReactСообщество изучает возможность использованияReactСинтаксис программы для разработки небольшого способа, один из более известных проектовTaro,nanachi. при использованииReactСложность апплета разработки грамматики в основном заключается вJSXГрамматически,JSXПо сутиJS, что слишком гибко по сравнению со статическим шаблоном небольшой программы. Новая идея, упомянутая в этой статье, состоит в том, чтобы иметь дело сJSXНовые представления о грамматике, представляющей собой более динамичный процесс мышления, по сравнению с существующей схемой, в принципе не ограничивают никаких ограничений.JSXНаписание, позвольте вамНастоящий способ ReactИмея дело с небольшими программами, я надеюсь, что эта новая идея может дать любому, кто заинтересован в использованииReactВдохновение от людей, которые разработали апплет.

Ограничения существующего мышления

Прежде чем предлагать новые идеи, давайте взглянем наTaro(最新版1.3),nanachiЭто как небольшая побочная программа обработкиJSXграмматический. Проще говоря, в основном черезфаза компиляцииПучокJSXПреобразование в эквивалентный апплетwxmlприходитьReactКод работает на стороне апплета.

Например, какReactлогическое выражение:

xx && <Text>Hello</Text>

будет преобразовано в эквивалентный апплет с директивой wx:if:

<Text wx:if="{{xx}}">Hello</Text>

СюдаJSXобработки, в основном вфаза компиляции, он зависит отфаза компиляцииизИнформацияКоллекция, взяв приведенный выше пример, должна определить логические выражения, а затем выполнить соответствующие действия.wx:ifконверсионная обработка.

Этофаза компиляцииКакие проблемы и ограничения? Проиллюстрируем следующим примером:

class App extends React.Component {
    render () {
        const a = <Text>Hello</Text>
        const b = a

        return (
            <View>
                {b}
            </View>
        )
    }
}

Сначала мы объявляемconst a = <Text>Hello</Text>, затем поставьтеaназначен наb, давайте посмотрим на последнюю версиюTaro 1.3преобразования, как показано ниже:

Этот пример не особенно сложен, но сообщает об ошибке.

Чтобы понять, почему приведенный выше код сообщает об ошибке, мы должны сначала понятьфаза компиляции. По сути, на этапе компиляции код представляет собой «строку», ифаза компиляцииПлан обработки, необходимо проанализировать нужную информацию из этой «строки» (черезAST, обычный и т. д.), а затем выполните соответствующую эквивалентную обработку преобразования.

Для приведенного выше примера, что нужно сделать эквивалентно? нуждаемся в насфаза компиляцииАнализbдаJSXФрагмент:b = a = <Text>Hello</Text>, затем поставьте<View>{b}</View>середина{b}Эквивалентно заменить на<Text>Hello</Text>. Однако вфаза компиляциичтобы быть увереннымbЗначение очень трудно. Некоторые люди говорят, что можно вернуться назад, чтобы определить значение b. Это не невозможно, но учтите это, потому чтоb = a, затем убедитесьaзначение, этоaКак определить его стоимость? нуждаться вbОпределяется в цепочке областей видимости, к которой можно получить доступa,ОднакоaВ свою очередь, может назначить другие переменные, после того, как ситуация не является простой заданием цикла, возникает во время такого вызова функции, функциональная информация о времени выполнения тройных решений, след не удалось, еслиaЭто переменная, висящая на глобальном объекте, и отследить ее тем более невозможно.

так вфаза компиляциине легко определитьbзначения.

Давайте подробнее рассмотрим сообщение об ошибке на изображении выше:a is not defined.

зачем говоритьaА как насчет неопределенного? Это связано с другой проблемой, мы знаем<Text>Hello</Text>, что на самом деле эквивалентноReact.createElement(Text, null, 'Hello'),а такжеReact.createElementВозвращаемое значение метода является обычнымJSобъект, как

// ReactElement对象
{
   tag: Text,
   props: null,
   children: 'Hello'
   ...
}

Таким образом, приведенный выше код находится вJSОперационная среда в реальном времени, вероятно, эквивалентна следующему:

class App extends React.Component {
    render () {
        const a = {
            tag: Text,
            props: null,
            children: 'Hello'
            ...
        }
        const b = a

        return {
            tag: View,
            props: null,
            children: b
            ...
        }
    }
}

Однако мы только что сказали, что этап компиляции требуетJSXЧтобы сделать эквивалентную обработку, вам нужно поставитьJSXПеревести вwxml,так<Text>Hello</Text>этоJSXФрагменты обрабатываются особым образом,aЭто больше не обычноеjsОбъекты, здесь мы видимaПеременная даже теряется, что обнажает серьезную проблему:Семантика кода нарушена, то есть из-за схемы времени компиляции дляJSXспециальная обработка, семантика кода, фактически работающего в апплете, отличается от того, что вы ожидали. Это скорее головная боль.

новые идеи

потому чтовремя компиляцииСхема, с указанными выше ограничениями, часто вызывает у вас «я все еще пишуReact? "Это чувство.

Далее мы представляем совершенно новую идею обработки, которая используется во время работы апплета и реальногоReactпочти неразличим, не меняет семантику кода,JSXвыражения будут обрабатываться только какReact.createElementВызов метода, когда он на самом деле работает, это обычноеjs

Шаг 1: Дайте каждому независимомуJSXФрагменты однозначно идентифицируютсяuuid, предполагая, что у нас есть следующий код:

const a = <Text uuid="000001">Hello</Text>

const y = <View uuid="000002">
	<Image/>
	<Text/>
</View>

мы даемaфрагмент,yфрагмент добавленuuidАтрибуты

Шаг второй:ReactКодbabelПереход к коду, который апплет может распознать, например.JSXФрагмент с эквивалентомReact.createElementзаменить и т.д.

const a = React.createElement(Text, {
  uuid: "000001"
}, "Hello");

Шаг 3: Извлеките каждый независимыйJSXФрагмент с апплетомtemplateупаковать, сгенерироватьwxmlдокумент

<template name="000001">
	<Text>Hello</Text>
</template>

<template name="000002">
	<View uuid="000002">
		<Image/>
		<Text/>
	</View>
</template>


<!--占位template-->
<template is="{{uiDes.name}}" data="{{...uiDes}}"/>

Обратите внимание на каждыйtemplateизnameлоготип иJSXУникальный идентификатор фрагментаuuidэто то же самое. Наконец, в конце необходимо сгенерировать шаблон-заполнитель:<template is="{{uiDes.name}}" data="{{...uiDes}}"/>.

Шаг 4: изменитьReactDOM.renderрекурсия (React 16.xПосле этого не рекурсивным способом) процесс, рекурсивная фаза выполнения, агрегацияJSXсегментированныйuuidсвойства, генерировать и возвращатьuiDesструктура данных.

Пятый шаг: сгенерирован четвертый шагuiDes, передается в среду апплета, апплетuiDesУстановить шаблон заполнителя<template is="{{uiDes.name}}" data="{{...uiDes}}"/>, который отображает окончательный вид.

Мы используем вышеперечисленноеAppпример компонента, чтобы проиллюстрировать весь процесс, сначалаjsКод будет экранирован как:

class App extends React.Component {
	render () {
	    const a = React.createElement(Text, {uuid: "000001"}, "Hello");
	    const b = a
	    
	    return (
	      React.createElement(View, {uuid: "000002"} , b);
	    )
	  }
}

При созданииwxmlдокумент:

<template name="000001">
	<Text>Hello</Text>
</template>

<template name="000002">
	<View>
		<template is="{{child0001.name}}" data="{{...child0001}}"/>
	</View>
</template>

<!--占位template-->
<template is="{{uiDes.name}}" data="{{...uiDes}}"/>

После использования нашего пользовательскогоrenderвоплощать в жизньReactDOM.render(<App/>, parent). существуетrenderВ рекурсивном процессе помимо рутинного создания экземпляров компонентов и выполнения жизненного цикла будет выполняться дополнительный сбор компонентов в процессе выполнения.uuidидентификация, последнее поколениеuiDesобъект

const uiDes = {
	name: "000002",
	
    child0001: {
   	    name: 000001,
   	    ...
   }
   
   ...
}

Эта небольшая программа, чтобы получитьuiDes, установите шаблон заполнителя<template is="{{uiDes.name}}" data="{{...uiDes}}"/>. Наконец визуализируйте представление апплета.

В течение всего этого процесса все вашиJSкод работает вReact过程середина,,JSXФрагменты также не получают никакой специальной обработки, простоReact.createElementвызова, дополнительно из-заReact过程просто чистыйjsОперации выполняются очень быстро, обычно всего несколько мс. в конечном итоге выведетuiDesданные в апплет, апплет передает этоuiDesВизуализируйте вид.

Теперь мы смотрим на предыдущее заданиеconst b = a, проблем не будет, потому чтоaНо обычные предметы. В дополнение к общемуОграничения схемы времени компиляции, например, любая функция, возвращающаяJSXФрагменты, динамически генерируемыеJSXфрагмент,forперерабатыватьJSXФрагменты и т. д. могут быть полностью отброшены, потому чтоJSXФрагменты простоjsобъект, вы можете делать все, что хотите, в конце концовReactDOM.renderсоберу всеФрагмент результата выполненияизuuidОпределить, сгенерироватьuiDes, и апплетuiDesСтруктура данных отображает окончательный вид.

Можно видеть, что этот новый способ мышления и предыдущийвремя компиляцииЕсть еще большая разница в планах, не так ли?JSXСегмент обработки динамический, вы можете делать это где угодно, любая функция любогоJSXФрагмент, окончательный результат выполнения будет определять, какой фрагмент отображать, только фрагмент результата выполненияuuidбудет написаноuiDes. с участиемвремя компиляцииСтатическая идентификация схемы принципиально иная.

Эпилог

«Обсуждение дешево. Покажи мне свой код!» Это просто идея? Или есть уже полная реализация?

полностью реализуется,alitaпроект в процессеJSXПри использовании грамматики эта идея перенимается, что такжеalitaПричина, по которой весь проект React Native можно трансформировать, не ограничивая метод написания, в основном, вдобавокalitaВ этом образе мышления было сделано много оптимизаций. Если вам интересна конкретная реализация этой идеи, вы можете изучить ееalitaИсходный код, это полностью открытый исходный кодGitHub.com/are slabs/Али....

Конечно, вы также можете построить свой собственный, основанный на этой идее.Схема разработки апплета React.