Проблема
У нас есть шаблон в нашей кодовой базе 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, чтобы обернуть вашу голову, но, без сомнения, вы скоро будете разбивать такие строки, не беспокоясь ни о чем!