Проблема

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

<Heading
  {...(error && {tone: 'danger'})}
>
  Title is here
</Heading>

Нужно обработать много скобок, так что же они все делают?

Разрушая это

По сути, чтобы понять, что здесь происходит, полезно немного подумать о том, что делает jsx. Возьмем хороший простой пример:

<Heading
  tone='danger'
>

Это читается так, как будто tone — это просто обычный старый атрибут обычного старого элемента Heading html — точно так же, как установка src для <img> и т. д. Это прекрасная вещь в синтаксисе jsx, который предоставляет React.

Однако за кулисами tone='danger' на самом деле добавляет пару ключ-значение к объекту javascript. Это становится очевидным, если убрать синтаксис jsx и посмотреть, как работает React.createElement():

function Greeting({ name }) {
  return createElement(
    Heading,
    { tone: 'danger' },
    'Title is here'
  );
}

Мы видим, что вторым аргументом функции createElement является объект props, указывающий свойства, которые должны быть применены к элементу Heading — в данном случае просто {tone: ‘danger'}.

Добавление к объекту javascript

Итак, каждый раз, когда мы добавляем свойства к компоненту Heading, написав tone='danger', или fontWeight='bold', или level='5', мы просто добавляем еще одну пару ключ-значение к объекту javascript под капотом.

Полностью отойдя на мгновение от jsx, давайте вспомним, что когда мы пишем старый добрый javascript, мы можем добавлять пары ключ-значение к объекту, используя оператор распространения:

const colorInfo = { tone: 'danger', backgroundColor: 'dangerWeak' };

const props = { fontWeight: 'bold' , level: '5', ...colorInfo };
// { fontWeight: 'bold' , level: '5', tone: 'danger', backgroundColor: 'dangerWeak' }

Здесь мы просто распространяем содержимое объекта colorInfo в объект props.

Эквивалентные синтаксисы

Имея эти объяснения, мы можем понять, почему это эквивалентные синтаксисы:

<Heading
 {...{tone: 'danger'}}
>

// IS THE SAME AS

<Heading
  tone='danger'
>

Потому что {…{tone: ‘danger’}} просто распространяет содержимое javascript object{tone: ‘danger’} в объект реквизита для Heading.

Это все еще выглядит немного запутанно из-за фигурных скобок, окружающих …{tone: ‘danger’}. Эти фигурные скобки просто говорят React «Эй, берегись, это просто обычный старый javascript, а не jsx!». Различное значение этих двух наборов фигурных скобок является основным источником путаницы.

Собираем все вместе

В конце концов, мы на самом деле хотели понять выражение, в котором происходит немного больше:

<Heading
  {...(error && {tone: 'danger'})}
>
  Title is here
</Heading>

Здесь мы, наконец, можем понять, почему может быть полезно использовать этот синтаксис распространения объектов. Потому что только ИНОГДА мы хотим задать тон опасности - только когда есть ошибка. И теперь мы можем указать это довольно кратко.

Логическое И && гарантирует, что error && {tone: 'danger'} вернет false, если ошибки нет, и вернет значение последнего операнда ({tone: 'danger'} ), если есть ошибка.

Затем мы заключаем это в круглые скобки и распространяем все, что он возвращает, на объект prop ofHeading. Если это false, в объект реквизита ничего не распространяется. В противном случае содержимое {tone: 'danger'} распространяется на объект — как раз то, что мы хотели!

Заключение

Я надеюсь, что это было несколько полезным объяснением. Я изо всех сил пытался найти объяснение именно этого варианта использования в Интернете, поэтому решил попробовать сам. Там довольно много синтаксического сахара javascript, используемого в действительно компактном пространстве, и некоторые концепции jsx, чтобы обернуть вашу голову, но, без сомнения, вы скоро будете разбивать такие строки, не беспокоясь ни о чем!