Книга: React.js. Быстрый старт
Назад: 3. Excel: необычный табличный компонент
Дальше: 5. Настройки для разработки приложения

4. JSX

До сих пор в книге рассматривались способы определения пользовательских интерфейсов в функциях render() с использованием вызовов методов React.createElement() и семейства методов React.DOM.* (например, метода React.DOM.span()). Среди не­удобств, создаваемых множеством вызовов функций, можно отметить трудность отслеживания расстановки всех необходимых закрывающих круглых и фигурных скобок. Но есть более простой способ определения пользовательских интерфейсов — использование JSX.

JSX представляет собой отдельную от React технологию, и ее применение не носит обязательного характера. Как вы видели, в первых трех главах она так ни разу и не использовалась. Вы можете вообще отказаться от JSX. Но все же высока вероятность того, что, один раз попробовав, вы уже не захотите возвращаться к вызовам функций.

161272.png

Не совсем понятно, что именно означает акроним JSX, но наиболее вероятно это сокращение от термина JavaScriptXML или JavaScript Syntax eXtension. Официальная страница проекта находится по адресу /.

Привет, JSX

Еще раз посмотрим на окончательный вариант примера Hello World из главы 1:

<script src="react/build/react.js"></script>

<script src="react/build/react-dom.js"></script>

<script>

  ReactDOM.render(

    React.DOM.h1(

      {id: "my-heading"},

      React.DOM.span(null,

        React.DOM.em(null, "Hell"),

        "o"

      ),

      " world!"

    ),

  document.getElementById('app')

  );

</script>

В функции render() имеется довольно много вызовов других функций. Использование JSX существенно упрощает код:

ReactDOM.render(

  <h1 id="my-heading">

    <span><em>Hell</em>o</span> world!

  </h1>,

  document.getElementById('app')

);

Этот синтаксис очень похож на уже известный вам HTML. Есть только одна загвоздка: поскольку этот код не является допустимым синтаксисом JavaScript, его нельзя запустить в браузере в неизменном виде. Это код следует преобразовать (транспилировать) в чистый JavaScript, который может быть запущен брау­зером.

Транспиляция JSX

Процесс транспиляции заключается в том, что берется исходный код и переписывается с целью получения таких же результатов, но уже с использованием синтаксиса, понимаемого устаревшими брау­зерами. Этот процесс отличается от использования полифиллов.

Примером полифилла может служить добавление к Array.pro­totype метода, аналогичного методу map(), который был введен стандартом ECMAScript5, чтобы заставить его работать в браузерах, поддерживающих стандарт ECMAScript3:

if (!Array.prototype.map) {

  Array.prototype.map = function() {

    // реализация метода

  };

}

 

// использование

typeof [].map === 'function';

// true, теперь 'map()' можно использовать

Полифилл представляет собой решение из области чистого JavaScript. Он хорошо справляется с поставленной задачей при добавлении новых методов к существующим объектам или при реализации новых объектов (например, JSON). Но когда в язык вводится новый синтаксис, этого недостаточно. Такой синтаксис, например вводящий в работу ключевое слово class, недопустим и вызывает в браузерах без поддержки class ошибку анализа кода, а создать для него полифилл не представляется возможным. Поэтому для нового синтаксиса требуется проведение компиляции (транспиляции), чтобы преобразовать его до того, как он будет представлен для обработки браузером.

Транспиляция JavaScript проводится довольно часто, поскольку программистам хочется использовать функциональные возможности, объявленные в стандарте ECMAScript6 (известном также как ECMAScript2015) и в последующих стандартах, не дожидаясь выхода поддерживающих эти возможности браузеров. Если у вас уже есть отработанный процесс сборки (который выполняет, к примеру, минификацию или ECMAScript6-to-5-транспиляцию), можно просто добавить к нему этап JSX-преобразования. Но предположим, что у вас еще нет процесса сборки, и пройдем все этапы настройки упрощенного процесса на стороне клиента.

Babel

Babel (ранее известный как 6to5) является транспилятором с открытым кодом, поддерживающим самые последние функциональные возможности JavaScript, а также включающим поддержку JSX. Он необходим как предварительное условие для использования JSX. В следующей главе будет показано, как настроить процесс сборки, позволяющий вам поставлять React-приложения реальным пользователям. Но в целях изучения JSX не будем ничего усложнять и проведем транспиляцию на стороне клиента.

161277.png

Необходимое предупреждение: преобразование на стороне клиента предназначено исключительно для создания прототипов, обучения и проведения исследований. Из соображений производительности такое преобразование в приложениях, предназначенных для обычного применения, использоваться не должно.

Для внутрибраузерных преобразований (на стороне клиента) нужен файл browser.js. В Babel, начиная с версии 6, он больше не предоставляется, но вы всегда можете взять последнюю работоспособную копию этого файла:

$ mkdir ~/reactbook/babel

$ cd ~/reactbook/babel

$ curl -

170997.pngcore/5.8.34/browser.js >

browser.js

 

161282.png

До выхода версии v0.14 React включал выполняемый на стороне клиента сценарий JSXTransformer. Кроме этого, в предыдущих версиях NPM-пакет react-tools устанавливал утилиту командной строки jsx. Теперь они считаются устаревшими и приоритет отдается транспилятору Babel.

Клиентская сторона

Чтобы JSX заработал, на вашей странице нужно сделать две вещи:

включить browser.js, сценарий, позволяющий транспилировать JSX;

пометить теги script, использующие JSX, чтобы Babel знал, что для него в этих тегах есть работа.

До сих пор все примеры в этой книге включали библиотеку React, используя для этого следующий код:

<script src="react/build/react.js"></script>

<script src="react/build/react-dom.js"></script>

Теперь нужно включить еще и преобразователь:

<script src="react/build/react.js"></script>

<script src="react/build/react-dom.js"></script>

<script src="babel/browser.js"></script>

Второй шаг — добавление в теги <script> атрибута type со значением text/babel (которое не поддерживается браузерами) — там, где их содержимое требует преобразования.

До:

<script>

  ReactDOM.render(/*...*/);

</script>

После:

<script type="text/babel">

  ReactDOM.render(/*...*/);

</script>

При загрузке страницы запускается код browser.js, который находит все сценарии text/babel и преобразует их содержимое в код, который может использоваться браузером. На рис. 4.1 показано, что произойдет в браузере Chrome при попытке запуска сценария с синтаксисом JSX в его исходном виде. Как и ожидалось, будет получена ошибка синтаксиса.

04_01.tif 

Рис. 4.1. Браузеры не понимают JSX-синтаксис

На рис. 4.2 можно увидеть, что после того, как сценарий browser.js провел транспиляцию блоков сценариев с атрибутом type="text/babel", страница заработала успешно.

04_02.tif 

Рис. 4.2. Браузерный сценарий Babel  и тип содержимого text/babel

О преобразовании JSX

Для проведения экспериментов и ознакомления с преобразованиями JSX вы можете воспользоваться интерактивным редактором, находящимся по адресу / (рис. 4.3).

04_03.tif 

Рис. 4.3. Интерактивное средство преобразования JSX

На рис. 4.4 можно увидеть, что преобразование JSX осуществляется легко и просто: исходный JSX-код Hello World становится серией вызовов React.createElement() с использованием функционального синтаксиса, с которым вы уже знакомы. Это обычный код JavaScript, поэтому он легко читается и понимается.

04_04.tif 

Рис. 4.4. Преобразованный пример Hello World

Есть еще одно интерактивное инструментальное средство, которое может пригодиться при изучении JSX или при переводе существующей разметки приложения из HTML, — преобразователь HTML-to-JSX (рис. 4.5).

04_05.tif 

Рис. 4.5. Инструментальное средство HTML-to-JSX

JavaScript в JSX

Зачастую при создании пользовательского интерфейса нужно применять переменные, условные выражения и циклы. Вместо того чтобы выдумывать еще один шаблонный синтаксис, можно воспользоваться тем, что JSX позволяет работать с кодом JavaScript внутри разметки. Вам нужно только заключить свой код JavaScript в фигурные скобки.

Рассмотрим пример компонента Excel из предыдущей главы. При замене функционального синтаксиса кодом JSX в конечном итоге будет получено примерно следующее:

var Excel = React.createClass({

 

  /* фрагмент... */

 

  render: function() {

    var state = this.state;

    return (

      <table>

        <thead onClick={this._sort}>

          <tr>

            {this.props.headers.map(function(title, idx) {

                if (state.sortby === idx) {

                title += state.descending ? ' \u2191' : ' \u2193';

               }

              return <th key={idx}>{title}</th>;

            })}

          </tr>

        </thead>

        <tbody>

          {state.data.map(function(row, idx) {

            return (

              <tr key={idx}>

                {row.map(function(cell, idx) {

                  return <td key={idx}>{cell}</td>;

                })}

              </tr>

            );

           })}

        </tbody>

      </table>

    );

}

});

Как видите, чтобы воспользоваться переменными, их заключают в фигурные скобки:

<th key={idx}>{title}</th>

Для циклов можно заключить в фигурные скобки в том числе map():

<tr key={idx}>

  {row.map(function(cell, idx) {

    return <td key={idx}>{cell}</td>;

  })}

</tr>

Код JavaScript в JSX может быть вложен на любую необходимую глубину. Код JSX можно воспринимать как JavaScript (после небольшого преобразования), но со знакомым синтаксисом HTML. С написанием кода JSX могут справиться даже те члены вашей команды, которые разбираются в JavaScript хуже вас, но при этом неплохо знают HTML. А для построения пользовательского интерфейса с живыми данными они могут изучить JavaScript в минимально необходимом объеме, всего лишь на уровне использования переменных и циклов.

В только что приведенном примере с компонентом Excel в функции обратного вызова map() есть условное выражение if. Хотя это условие и является вложенным, после небольшого дополнительного форматирования его можно превратить в легкочитаемый единый оператор, использующий три операнда:

return (

  <th key={idx}>{

    state.sortby === idx

      ? state.descending

        ? title + ' \u2191'

        : title + ' \u2193'

      : title

  }</th>

);

161287.png

Заметили повторяющуюся переменную title в последнем примере? От этого повторения можно избавиться:

return (

  <th key={idx}>{title}{

    state.sortby === idx

      ? state.descending

        ? ' \u2191'

        : ' \u2193'

      : null

  }</th>

);

Однако в таком случае придется модифицировать имеющуюся в примере функцию сортировки. В этой функции предусматривается, что пользователь будет щелкать на элементе <th>, а для определения, на каком именно элементе <th> был произведен щелчок, будет использоваться метод cellIndex. Но когда в коде JSX имеются смежные блоки {}, для их обособления применяются теги <span>. Иными словами, фрагмент кода <th>{1}{2}</th> превращается в DOM-модели в код <th><span>1</span><span>2</span></th>.

Пробельные символы  в JSX

Пробельные символы воспринимаются в коде JSX почти так же, как и в коде HTML, но с небольшими отличиями:

<h1>

  {1} plus {2} is   {3}

</h1>

превращается в:

<h1>

  <span>1</span><span> plus </span><span>2</span><span>

    is </span><span>3</span>

</h1>

что отображается как 1 plus 2 is 3 — в точном соответствии с вашими ожиданиями по части HTML: несколько пробелов становятся одним пробелом.

Но в этом примере:

<h1>

  {1}

  plus

  {2}

  is

  {3}

</h1>

вы в конечном итоге получаете следующий код:

<h1>

  <span>1</span><span>plus</span><span>2</span><span>is

171000.png</span><span>3</span>

</h1>

Как видите, все пробельные символы вырезаны, поэтому конечный результат будет 1plus2is3. Там, где нужно, пробел можно всегда добавить с помощью конструкции {' '} (которая затем плодит еще больше тегов <span>) или же превратить строки символов в выражения и добавить пробел уже там. Иными словами, будут работать оба следующих варианта:

<h1>

  {/* пробельные выражения */}

  {1}

  {' '}plus{' '}

  {2}

  {' '}is{' '}

  {3}

</h1>

 

<h1>

  {/* пробел, прикрепленный к строковым выражениям */}

  {1}

  {' plus '}

  {2}

  {' is '}

  {3}

</h1>

Комментарии в JSX

В предыдущих примерах за счет добавления комментариев к разметке JSX можно увидеть, как в код внедряется новая концепция.

Поскольку выражение, заключенное в фигурные скобки {}, является всего лишь кодом JavaScript, можно легко добавить многострочный комментарий, воспользовавшись следующей конструкцией: /* комментарий */.

Можно также добавить комментарий в строку, воспользова­вшись синтаксисом // комментарий, но при этом не стоит забывать про закрывающую фигурную скобку (}) выражения, которая должна быть на другой строке, чтобы не выглядеть как часть комментария:

<h1>

  {/* многострочный комментарий */}

  {/*

    multi

    line

    comment

  */}

  {

    // однострочный комментарий

  }

  Hello

</h1>

Поскольку код {// комментарий} не работает (} теперь закомментирована), от использования однострочных комментариев мало проку, и все комментарии можно привести к единому виду, выбрав во всех случаях формат многострочного комментария.

Элементы HTML

В JSX допускается использование элементов HTML:

<h2>

  More info &raquo;

</h2>

Этот пример, как показано на рис. 4.6, выдает правую угловую кавычку.

04_06.tif 

Рис. 4.6. HTML-элемент в JSX

Но, если воспользоваться элементом в качестве части выражения, вы окажетесь в ситуации, когда элемент будет закодирован дважды. В этом примере:

<h2>

  {"More info &raquo;"}

</h2>

HTML-элемент будет закодирован — и вы увидите результат, показанный на рис. 4.7.

04_07.tif 

Рис. 4.7. Дважды закодированный элемент HTML

Чтобы избавиться от двойного кодирования, можно воспользоваться Юникод-версией элемента HTML, в данном случае \u00bb (см. ):

<h2>

  {"More info \u00bb"}

</h2>

Для удобства можно где-нибудь в верхней части модуля определить константу вместе с любым общим пробелом. Например:

const RAQUO = ' \u00bb';

Затем этой константой можно воспользоваться в любом нужном месте:

<h2>

  {"More info" + RAQUO}

</h2>

<h2>

  {"More info"}{RAQUO}

</h2>

161293.png

Обратили внимание на использование const вместо var? Добро пожаловать в прекрасный новый мир Babel, где можно побаловать себя всеми новшествами, предлагаемыми современным JavaScript. Подробности рассматриваются в главе 5.

Анти-XSS

Можно задаться вопросом: а зачем идти по такому сложному пути, как использование элементов HTML? Потому что здравый смысл подсказывает: они помогают бороться с XSS-атаками.

React нейтрализует все строки, противодействуя атакам класса XSS. Поэтому, когда у пользователей запрашивается какой-нибудь ввод, а они предоставляют вредоносную строку, React защищает вас от атаки. Возьмем, к примеру, следующий пользовательский ввод:

var firstname = 'John<scr'+'ipt

  src=">';

При определенных обстоятельствах вы можете вписать его в DOM-модель. Например:

document.write(firstname);

Это будет иметь катастрофические последствия, поскольку на странице появится John, а тег <script> приведет к загрузке вредоносного кода JavaScript и откроет несанкционированный доступ к вашему приложению и конфиденциальной информации доверившихся вам пользователей.

React защищает от подобных случаев, и от вас не требуется никаких усилий. Если создать следующий код:

React.render(

  <h2>

    Hello {firstname}!

  </h2>,

  document.getElementById('app')

);

то React нейтрализует содержимое переменной firstname (рис. 4.8).

04_08.tif 

Рис. 4.8. Нейтрализация строк

Распространяемые атрибуты

В JSX у ECMAScript6 было позаимствовано весьма полезное свойство под названием оператор распространения, которое было внедрено в качестве удобного усовершенствования при работе с определением свойств.

Представьте, что у вас есть коллекция атрибутов, которую нужно передать компоненту <a>:

var attr = {

  href: '',

  target: '_blank',

};

Вы можете сделать это в любой момент с помощью следующего кода:

return (

  <a

    href={attr.href}

    target={attr.target}>

    Hello

  </a>

);

Но, похоже, возникает проблема использования часто повторяющегося шаблонного кода. С помощью распространяемых атрибутов эту задачу можно выполнить всего лишь в одной строке кода:

return <a {...attr}>Hello</a>;

В примере у вас есть объект атрибутов, который вы хотите определить (возможно, при некоторых условиях) заранее. Это полезно уже само по себе, но чаще всего применяется вариант, при котором данный объект будет получен извне, зачастую из родительского компонента. Именно такой случай и рассмотрим.

Атрибуты, распространяемые от родительского к дочернему компоненту. Представьте, что вы создаете компонент FancyLink, закулисно использующий обычный компонент <a>. Желательно, чтобы ваш компонент принял все те же атрибуты, что и <a> (href, style, target и т.д.), плюс дополнительный атрибут (скажем, size). Итак, кто-нибудь может воспользоваться вашим компонентом следующим образом:

<FancyLink

  href=""

  style={ {color: "red"} }

  target="_blank"

  size="medium">

  Hello

</FancyLink>

Как ваша функция render() сможет воспользоваться распространяемыми атрибутами и избежать повторного определения всех свойств компонента <a>?

var FancyLink = React.createClass({

  render: function() {

    switch(this.props.size) {

      // совершение каких-либо действий на основе свойства 'size'

    }

    return <a {...this.props}>{this.props.children}</a>;

  }

});

161299.png

Вы заметили использование метода this.props.children? Это простой и удобный метод, позволяющий переправлять вашему компоненту любое количество дочерних компонентов и обращаться к ним при составлении интерфейса.

В предыдущем фрагменте кода вы выполняете все нужные действия на основе значения свойства size, а затем переносите все свойства в <a> (включая и свойство size). Компонент React.DOM.a не имеет ни малейшего понятия о свойстве size, поэтому он его молча игнорирует, а все остальные свойства использует.

Можно немного улучшить код и не переправлять ненужные свойства:

var FancyLink = React.createClass({

  render: function() {

 

    switch(this.props.size) {

      // совершение каких-либо действий на основе свойства 'size'

    }

 

    var attribs = Object.assign({}, this.props); // поверхностное

                                                 // клонирование

    delete attribs.size;

 

    return <a {...attribs}>{this.props.children}</a>;

  }

});

161304.png

Если воспользоваться синтаксисом, предлагаемым ECMAScript7 (бесплатно поставляемым вам инструментальным средством Babel!), решение задачи упрощается еще больше и обходится без всякого клонирования:

var FancyLink = React.createClass({

  render: function() {

 

    var {size, ...attribs} = this.props;

 

    switch (size) {

      // совершение каких-либо действий

      // на основе свойства 'size'

    }

 

    return <a {...attribs}>{this.props.children}</a>;

  }

});

Возвращение в JSX нескольких узлов

Из вашей функции render() всегда нужно возвращать один узел. Возвращать два узла не разрешается. Иными словами, следующий код считается ошибочным:

// Синтаксическая ошибка, связанная с необходимостью

// заключения смежных элементов JSX в охватывающий тег

 

var Example = React.createClass({

  render: function() {

    return (

      <span>

        Hello

      </span>

      <span>

        World

      </span>

    );

  }

});

Исправить ошибку нетрудно, нужно просто заключить все узлы в другой компонент, например в <div>:

var Example = React.createClass({

  render: function() {

    return (

      <div>

        <span>

          Hello

        </span>

        <span>

          World

        </span>

      </div>

    );

  }

});

Хотя возвратить из вашей функции render() массив узлов невозможно, массивы можно использовать при построении композиции — при условии, что у узлов в массиве имеются надлежащие ключевые атрибуты key:

var Example = React.createClass({

  render: function() {

 

    var greeting = [

      <span key="greet">Hello</span>,

      ' ',

      <span key="world">World</span>,

      '!'

    ];

 

    return (

      <div>

        {greeting}

      </div>

    );

  }

});

Обратите внимание на то, как в массив вставляются пробельные символы и другие строки, а также на то, что им не нужен ключ.

Это похоже на принятие любого количества дочерних компонентов, переданных от родительского компонента, и на их распространение в вашей функции render():

var Example = React.createClass({

  render: function() {

    console.log(this.props.children.length); // 4

    return (

      <div>

        {this.props.children}

      </div>

    );

  }

});

 

React.render(

  <Example>

    <span key="greet">Hello</span>

      {' '}

    <span key="world">World</span>

    !

  </Example>,

  document.getElementById('app')

);

Отличия JSX от HTML

Код JSX выглядит знакомо, поскольку похож на код HTML, но имеет преимущество — простой способ добавления динамических значений, циклов и условных выражений (нужно лишь заключить их в фигурные скобки {}). Для начала работы с JSX всегда можно воспользоваться инструментальным средством HTML-to-JSX, но чем раньше вы станете набирать свой собственный код JSX, тем лучше. Рассмотрим некоторые (возможно, несколько необычные для вас на начальном этапе обучения) различия между HTML и JSX. Кое-какие различия уже рассматривались в главе 1, но бегло повторим еще раз.

Просто class использовать нельзя, а как насчет for?

Вместо атрибутов class и for (оба они являются в ECMAScript зарезервированными словами) следует использовать названия className и htmlFor:

// Недопустимо!

var em = <em class="important" />;

var label = <label for="thatInput" />;

 

// Допустимо

var em = <em className="important" />;

var label = <label htmlFor="thatInput" />;

style является объектом

Атрибут style получает в качестве значения объект, а не строку с разделителями в виде точки с запятой. Имена свойств CSS набираются в «верблюжьем» регистре и без дефисов:

// Недопустимо!

var em = <em style="font-size: 2em; line-height: 1.6" />;

 

// Допустимо

var styles = {

  fontSize: '2em',

  lineHeight: '1.6'

};

var em = <em style={styles} />;

 

// Также допустима встроенная форма записи

// обратите внимание на двойные фигурные скобки { {} } –

// один комплект для динамического значения в JSX,

// а второй – для JS-объекта

var em = <em style={ {fontSize: '2em', lineHeight: '1.6'} } />;

Закрывающие теги

В HTML некоторые теги не нуждаются в закрытии, а в JSX (XML) их закрывать обязательно:

// Недопустимо:

// незакрытых тегов быть не должно,

// даже если в HTML это вполне допустимо

var gimmeabreak = <br>;

var list = <ul><li>item</ul>;

var meta = <meta charset="utf-8">;

 

// Допустимо

var gimmeabreak = <br />;

var list = <ul><li>item</li></ul>;

var meta = <meta charSet="utf-8" />;

 

// или

var meta = <meta charSet="utf-8"></meta>;

Атрибуты в «верблюжьем» регистре

Вы обратили внимание, что в предыдущем фрагменте кода charset использована форма charSet? Все атрибуты в JSX должны быть указаны в «верблюжьем» регистре (camelCase). Поначалу это часто путает все карты — вы можете набрать onclick и заметить, что ничего не происходит, до тех пор пока не вернетесь к этому месту кода и не измените прежний код на onClick:

// Недопустимо!

var a = <a onclick="reticulateSplines()" />;

 

// Допустимо

var a = <a onClick={reticulateSplines} />;

Исключение из этого правила составляют все атрибуты с префиксами data- и aria-, они используются в таком же виде, как и в HTML.

JSX и формы

Имеются различия между JSX и HTML и при работе с формами. Посмотрим какие.

Обработчик события onChange

При использовании элементов формы пользователи вносят изменения в их значения. В React вы можете подписаться на такие изменения с помощью атрибутов onChange. Это куда логичнее использования значения checked для переключателей и флажков, а также selected — в элементах выбора <select>. При наборе в текстовых областях и полях <input type="text"> onChange активизируется по мере набора текста пользователем, что намного полезнее, чем активация при утрате элементом фокуса. Это означает, что подписываться на события мыши и клавиатуры для отслеживания набора текста при вводе изменений уже не нужно.

Сравнение value  и defaultValue

Если в HTML имеется тег <input id="i" value="hello" />, а затем значение атрибута value путем набора текста изменяется на "bye", то получается, что…

i.value; // "bye"

i.getAttribute('value'); // "hello"

В React содержимое свойства value всегда имеет последнее значение вводимого текста. Если нужно указать значение по умолчанию, можно воспользоваться свойством defaultValue.

В следующем фрагменте кода имеются компонент <input> с предварительно заполненным содержимым "hello" и обработчик события onChange. Удаление последнего «o» в "hello" приводит к тому, что у value появляется значение "hell", а значением свойства defaultValue остается "hello":

function log(event) {

  console.log("value: ", event.target.value);

  console.log("defaultValue: ", event.target.defaultValue);

}

React.render(

  <input defaultValue="hello" onChange={log} />,

  document.getElementById('app')

);

161311.png

Такой же схемы нужно придерживаться и в собственных компонентах: если в них допускается применение свойства, имя которого намекает на поддержку актуальности (например, value, data), то сохраняйте актуальность его значения. Если этого не нужно, назовите свойство initialData (как делали в главе 3) или как-нибудь вроде defaultValue, чтобы было ясно, чего от него ожидать.

Значение компонента <textarea>

Для соответствия полям текстового ввода в имеющейся в React версии <textarea> применяются свойства value и defaultValue. В value поддерживается актуальность, а в defaultValue сохраняется исходное значение. Если следовать HTML-стилю и воспользоваться для определения значения дочерним элементом textarea (что не рекомендуется делать), он будет рассматриваться как имеющий такое же значение, что и свойство defaultValue.

В HTML поле <textarea> (как определено консорциумом W3C) применяет в качестве своего значения дочерний элемент, чтобы разработчики могли использовать во вводе новые строки. Но React, построенная целиком на основе JavaScript, не страдает от этого ограничения. Когда нужна новая строка, просто используется комбинация символов \n.

Рассмотрим следующие примеры и результаты их выполнения, показанные на рис. 4.9:

function log(event) {

  console.log(event.target.value);

  console.log(event.target.defaultValue);

}

 

React.render(

  <textarea defaultValue="hello\nworld" onChange={log} />,

  document.getElementById('app1')

);

React.render(

  <textarea defaultValue={"hello\nworld"} onChange={log} />,

  document.getElementById('app2')

);

React.render(

  <textarea onChange={log}>hello

world

  </textarea>,

  document.getElementById('app3')

);

React.render(

  <textarea onChange={log}>{"hello\n\

    world"}

  </textarea>,

  document.getElementById('app4')

);

04_09.tif 

Рис. 4.9. Новые строки в текстовых областях

Обратите внимание на разницу между использованием в качестве значения свойства строки символов "hello\nworld" и использованием строки JavaScript {"hello\nworld"}.

Также возьмите на заметку, что многострочное строковое значение в JavaScript нуждается в нейтрализации с помощью обратного слеша, \ (четвертый пример).

И наконец, посмотрите, как React выдает предупреждение об использовании для установки значения традиционного дочернего элемента, принадлежащего <textarea>.

Значение компонента <select>

Когда в HTML используется поле ввода <select>, предварительно выбранные записи указываются с помощью <option selected>:

<!-- традиционный HTML-код -->

<select>

  <option value="stay">Should I stay</option>

  <option value="move" selected>or should I go</option>

</select>

В React для компонента <select> указывается value или же (что еще лучше) defaultValue:

// React/JSX

<select defaultValue="move">

  <option value="stay">Should I stay</option>

  <option value="move">or should I go</option>

</select>

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

<select defaultValue={["stay", "move"]} multiple={true}>

  <option value="stay">Should I stay</option>

  <option value="move">or should I go</option>

  <option value="trouble">If I stay it will be trouble</option>

</select>

161320.png

Если вы перепутаете код с HTML и установите для <option> атрибут selected, то React выдаст предупреждение.

Разрешается вместо записи <select defaultValue> использовать <select value>, хотя делать это не рекомендуется, поскольку вам придется позаботиться об обновлении значения, которое видит пользователь. В противном случае, когда пользователь выбирает другой вариант, компонент <select> сохраняет прежний вид. Иными словами, вам нужен код, похожий на следующий:

var MySelect = React.createClass({

  getInitialState: function() {

    return {value: 'move'};

  },

  _onChange: function(event) {

    this.setState({value: event.target.value});

  },

  render: function() {

    return (

      <select value={this.state.value}

        onChange={this._onChange}>

        <option value="stay">Should I stay</option>

        <option value="move">or should I go</option>

        <option value="trouble">If I stay it will be

          trouble</option>

      </select>

    );

  }

});

Компонент Excel в JSX

В завершение воспользуемся JSX и перепишем все методы render*() в финальной версии компонента Excel из предыдущей главы. Я предлагаю вам выполнить это упражнение самостоятельно (вы всегда сможете сравнить свое решение с примером из хранилища кода, сопровождающего эту книгу).

Назад: 3. Excel: необычный табличный компонент
Дальше: 5. Настройки для разработки приложения

DalExcax
Весьма полезная штука ---- продажа оборудования окон пвх Здесь не может быть ошибки? ---- магазин большой одежды для женщин Я думаю, что Вы ошибаетесь. Пишите мне в PM, пообщаемся. ---- купить землю в сочи под строительство Теперь всё понятно, большое спасибо за информацию. ---- фонарь bailong bl Это просто замечательный ответ ---- отдых на море краснодарский край Присоединяюсь. Всё выше сказанное правда. Можем пообщаться на эту тему. ---- купить дом в сочи Я извиняюсь, но, по-моему, Вы не правы. Пишите мне в PM, пообщаемся. ---- как правильно кидать снюс Конечно. И я с этим столкнулся. Можем пообщаться на эту тему. ---- пицца краснодар меню Офигенно! Спасибо!!! ---- где купить аккаунт фейсбук для рекламы По моему мнению Вы не правы. ---- колумб играть бесплатно без регистрации
AnthonyTap
Это условность, ни больше, ни меньше minecraft who killed noob
stilnyeokna
Высококачественные пластиковые окошки плюс двери ото прямого изготовителя дают возможность заказчику сделать вполне индивидуальный приобретение в надобном наличие, потому наш магазин хотим клиентам сделать самые качественный сервис по производству и доставке окошек к тому же дверных проемов от иркутского изготовителя. На сайте указанного компании изготовление окон Вы можете посмотреть изготавливаемый ассортимент такой уникальной дверей затем сделать оснащение для индивидуальное помещение, коттедж либо большого жилого жилья. Наша компания указана единственным изготовщиком, в которого покупатель напрямую сможете купить пластиковые или алюминиевые окошки или двери, остекление лоджии, фасадные ансамбли у помещение, двойные входные концепции также иные виды застекления для личного помещения. Не включая низких расценок без наценок плюс диллеров компания предоставляем новым заказчикам гибкую систему уценок до сорока пяти процентов, потому по нашем сайте пользователи имеют возможность заказать окна и двери вовсе не только в Иркутске, но и на ближнюю район страны.
ecorfru
Разработка проектов касательно экологической консультации также подобная услуги, сведенная на полевыми-экологическими анализом плюс разработкой плана всяческих направлений –такая обязательная процедура, что исполняется только по закону и предоставляет выполнение норм исходя с охране внешней сферы. Компания Сиблидер выполняет полноценный величину действий именно в теме окружающей среды и предоставляет именно Вам лучшие условия сотрудничества касательно исполнение системного аспекта разработки всех видов документов и аутсорсинга на счет экологии нашими профессионалами. На источнике указанной фирмы организация государственной экологической экспертизы Вы имеют возможность пролистать всяческие подтверждающие удостоверения также разрешение, еще и заказать рекомендации от наших менеджеров либо услуги, какие фирма предоставляет. Наша компания максимально качественно просмотрим ваш заказ затем указываем наилучшие пути резолюции любой случая в небольшой промежуток времени, также еще специалисты совершаем хорошее инжиниринг юрилического лица от самого старта также к завершению договора. Заполняйте номер телефону на страничке и делайте работу в руки специалистами в области экологии каковы клиентам содействуют.
LikefilmsNet
Киносайт – является место, собственно где кинозритель найдет индивидуально такое-же по своей вкусу, определенно не найдете лучшего отвлечения от вашего рутины, чем включение захватывающего сериала обожаемого почерка, тот что зритель выбираете по личное предпочтение. Сайт качественных кинотеатра Зверополис 2 (2022) смотреть мультфильм онлайн бесплатно вмещает огромную число известных кинолент последних выпусков плюс анонсы данного 2021 года, какие постоянные посетители смогут просмотреть полностью в открытом доступе плюс без личного кабинета. Приспособленная навигация по сайту фильмов, мультфильмов либо сериалов легко обозначит кино у хорошем разрешении и звук, также Вы постоянно можете разделить популярное фильм из личными знакомыми с помощью нажатия кнопки социальной сети также написать свой отзыв, есле ж предполагаете разделить первые впечатлениями из другими зрителями. Здесь на презентованном сайте разных фильмов зритель сумеет подобрать фильмы именно по стилю, годам либо рейтингу, заходите и всегда пересматривайте лучшим кинокартиной с большим восторгом на нашему Like Films .
hd1080pred
День кинофильмов сейчас есть целостная порция вашего досуга по вечернее время и в течении дня, на свободных днях и регулярно, в момент изоляции или же небольшим сообщества потому вполне ценно найти сайт высококачественных фильмов, что постоянно рядом с добавленных. На нашем веб-сайте сборника кино Смотреть фильм Гарри Поттер и Тайная комната (2002) онлайн бесплатно и в хорошем качестве, ценители высококачественных показа смогут найти пред вышедшее показ, серийное кино или мультики, или определить видеофильм по жанру. В случае если посетитель всемирный обожатель фильмов, тогда благодаря веб-сайте фильмов есть возможность создать личный аккаунт, чтоб сохранять примечания, обозначить фильм, тот что надо посмотреть. На нашей визитной шапке всегда можно отследить популярные сюжеты, каковы ожидают на больших экранах к тому же увидеть видеоролик, а ожидаемое фильмы мы предоставляем под наших читателей только с хорошем hd разрешении, потому уверенно можете входить на ресурс потом кликнуть «Старт» указанный кино.
KinogoBlue
Зачастую мучаетесь касательно предмету, что стоит запустить интересное на вечерний досуг? На нашем онлайн кинотеатре бесплатного плюс новых кино Киного Я иду искать (2019) смотреть онлайн бесплатно пользователи можете мгновенно обнаружить хороший вариант кинофильма распространенного стиля с подмогой функционала навигации, отбора или же окна ввода. Сайт все это определил за посетителей также разработали просмотр нового кино более проще, именно на начальной стороне Вы сможет обозреть вновь свежую кино, известные многосерийное кино также предельно высокие показы, ну а во время когда надумаете увидеть трейлеры мировых фильмов этого времени, тогда кликайте в шапку «В скором времени в кино» и включайте известные спешные фильмы в прокате. Короткое воссоздание сюжета, сформированный показатель со стороны пользователей и подходящие примечания подсказывают польователю подобрать кино, какое понравится вовсе не лишь посетителю, однако и всем близким. Кликайте и ищите новую фильмы непосредственно сегодня!