JSX: когда оцениваются выражения JavaScript?

После изучения руководств по GatsbyJS и React у меня сложилось впечатление, что выражения JavaScript всегда оцениваются, когда они заключены в {} скобки в JSX. Но теперь я смотрю на файл JSX внутри начального репозитория GatsbyJS, где похоже, что скобки вызывают другое поведение:

const {
    data: {
      posts: { edges: posts },
      site: {
        siteMetadata: { facebook }
      }
    }
} = props;

( Источник)

Согласно учебным пособиям, "facebook" должен оцениваться как JavaScript и должен возвращать undefined, но это не то, что происходит. Каким-то образом мы получаем объект JavaScript data.site.siteMetadata.facebook, в котором есть некоторые данные. Что тут происходит? Почему "facebook" не оценивается как выражение JavaScript?

1 ответ

Решение

Кусок кода, который вы копируете, на самом деле не имеет ничего общего с JSX (см. Ниже). Это синтаксис деструктуризации объекта ES6, как прокомментировал вопрос @PrithvirajSahu.

Скажем, у вас есть такой объект:

const obj = {
  a: 100, 
  b: { 
    value: 200,
  } 
};

Вы можете получить внутренние значения так:

const { a } = obj; 
// same as const a = obj.a

const { b: c } = obj; 
// same as const c = obj.b

const { b: { value } } = obj; 
// same as const value = obj.b.value

const { b: { value: v } } = obj; 
// same as const v = obj.b.value

const { a, { b: { value } } } = obj; 
// same as 
// const a = obj.a; 
// const value = obj.b.value;

Итак, вернемся к вашему коду, это эквивалентно

const posts = props.data.posts.edges;
const facebook = props.data.site.siteMetadata.facebook;

Как вы выяснили, синтаксис деструктурирования очень аккуратен на 1 или 2 уровнях, но его трудно прочитать, когда их больше. Лично я использую его только на 1 уровне.


Изменить: в функции в источнике, только строки, начинающиеся с <... такое синтаксис JSX

const CategoryPage = props => {
  // code here is normal js
  const { ... } = props;

  // JSX start from inside this return function
  return (
    <React.Fragment>
      { /* code between bracket in this section will be evaluate as 'normal JS' */ }
    </React.Fragment>
  )
}

Предостережение: код в скобках в JSX должен вычислять функцию. Если мы напишем что-то вроде этого:

<div className="container">
  Hello
  {"Happy"}
  World
</div>

Бабель превратит это в следующий регулярный JS:

React.createElement(
  "div",
  { className: "container" },
  "Hello",
  "Happy",
  "World"
);

Играть с бабел здесь

Все, что мы поместим между скобками, будет передано React.createElement как дитя div элемент; поэтому только действительный элемент React может быть размещен здесь:

  • Null (ничего не делать)
  • Строка (станет текстовым узлом DOM)
  • Еще один элемент React
  • Выражение / функция, которая оценивает или возвращает любое из вышеперечисленного
<div>
  { hasDate && <Date /> }
<div>

или же

// somewhere in the code
const showDate = (hasDate) => {
  if (!hasDate) return null;
  return <Date />
}

// in the render function
return (
  <div>
    { showDate(hasDate) }
  <div>
)

Мы также можем использовать скобку, чтобы передать значение реквизиту элемента:

<div 
  style={ { color: 'red' } }
  onClick={ (event) => {...} }>
  { hasDate && <Date /> }
<div>
Другие вопросы по тегам