Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  1. Главная
  2. Категории
  3. Фронтенд
  4. React
  5. Синтаксис JSX: списки и события

Синтаксис JSX: списки и события

Запланировано Прикреплена Закрыта Перенесена React
react
8 Сообщения 6 Постеры 86 Просмотры
  • Сначала старые
  • Сначала новые
  • По количеству голосов
Ответить
  • Ответить, создав новую тему
Авторизуйтесь, чтобы ответить
Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
  • kirilljsxK Не в сети
    kirilljsxK Не в сети
    kirilljsx
    js
    написал в отредактировано
    #1

    JSX — это не XML, а просто сахар

    JSX — это синтаксический сахар над React.createElement(), который позволяет писать HTML-подобный код прямо в JavaScript. И как по мне я его очень люблю, а с приходом Next.js так вообще работать с React одно удовольствие.

    Да: <div>Привет, JSX</div> — это валидный JS. Но не будем спешить радоваться: здесь есть свои подводные камни, особенно когда речь заходит о событиях и списках. Их разбирали уже много сотен раз, но я хочу поделиться своими мыслями и показать конкретные примеры.


    В отличие от нативного HTML, где мы пишете onclick, в JSX события пишутся в camelCase и передаются как функции, а не строки. То есть не onClick="handleClick()", а onClick={handleClick}. Обратим внимание на фигурные скобки и отсутствие кавычек — это не HTML!

    handleKeyUp

    function handleKeyUp(e) {
      document.getElementById('title').innerText = e.target.value;
    }
    

    Что происходит: Каждый раз, когда вы отпускаете клавишу в инпуте, функция лезет в DOM через document.getElementById и меняет текст элемента с id="title".

    Как применяется:

    <input onKeyUp={handleKeyUp} type="text" />
    

    Почему так делать НЕ НАДО:
    В React никогда не трогайте DOM напрямую (ну, кроме крайних случаев). Это как писать var вместо const — технически работает, но коллеги будут плакать. В реальности вы бы использовали useState и обновляли состояние.

    Но для примера сойдёт.


    handleClick

    function handleClick(e) {
      document.getElementById('title').innerText += ' ' + e.target.textContent;
    }
    

    Что происходит: При клике на кнопку к тексту заголовка добавляется пробел и текст самой кнопки (в нашем случае —: Строка).

    Как применяется:

    <button onClick={handleClick}>Строка</button>
    

    Лайфхак: Обратите внимание, что e.target.textContent — это содержимое кнопки. Так что если мы напишем <button>Клик!</button>, в заголовок добавится “Клик!”.


    handleMouseEnter / handleMouseLeave

    function handleMouseEnter(e) {
      e.target.classList.add('hover');
    }
    
    function handleMouseLeave(e) {
      e.target.classList.remove('hover');
    }
    

    Что происходит: При наведении курсора на кнопку добавляется класс hover, при уходе — удаляется. В CSS вы бы прописали стили для .hover, чтобы кнопка светилась, как неоновая вывеска.

    Как применяется:

    <button 
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      Кнопка
    </button>
    

    Для чего это нужно: Hover-эффекты — must-have для любого уважающего себя UI. Без них кнопки будут выглядеть как серые кирпичи.


    handleMouseDown / handleMouseUp

    function handleMouseDown(e) {
      e.target.classList.add('active');
    }
    
    function handleMouseUp(e) {
      e.target.classList.remove('active');
    }
    

    Что происходит: При нажатии кнопки (но не отпускании!) добавляется класс active. Это нужно, чтобы кнопка “проваливалась” при клике — стандартный паттерн для UX.

    Как применяется:

    <button
      onMouseDown={handleMouseDown}
      onMouseUp={handleMouseUp}
    >
      Кнопка
    </button>
    

    Важно: Не путайте onClick и onMouseDown! onClick сработает при отпускании кнопки мыши, а onMouseDown — при нажатии. Если нужно имитировать нажатие, как в реальной жизни — юзайте onMouseDown/onMouseUp.


    Списки в JSX: map() — ваш новый лучший друг

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

    Теперь про списки. В вашем коде три одинаковых кнопки с разными строками. Писать их вручную — как пилить воду топором. В React списки рендерятся через map(), а каждому элементу нужно задать ключ (key), чтобы React не тормозил.

    const emojis = ['Строка', 'Строка1', 'Строка2'];
    
    ReactDOM.render((
      <div>
        <input onKeyUp={handleKeyUp} type="text" />
        {emojis.map((emoji, index) => (
          <button
            key={index}
            onMouseEnter={handleMouseEnter}
            onClick={handleClick}
            onMouseLeave={handleMouseLeave}
            onMouseDown={handleMouseDown}
            onMouseUp={handleMouseUp}
          >
            {emoji}
          </button>
        ))}
      </div>
    ), document.querySelector('#root'));
    

    Что изменилось:

    • Создали массив эмодзи.
    • Проитерировались через map().
    • Добавили key={index} — без этого React будет ругаться в консоли (и правильно делает).

    Почему key обязателен?
    React использует ключи для отслеживания изменений в списке. Если вы уберёте key, при обновлении списка React будет перерисовывать всё подряд, а не только изменённые элементы. Это как пытаться найти иголку в стоге сена без метки.


    Частые ошибки новичков

    1. Не трогайте DOM напрямую
      Вместо document.getElementById юзайте useState и рефы (useRef). Иначе вы превратите React-приложение в jQuery-халтуру.

    2. Всегда задавайте key в списках
      И лучше не индекс (index), а уникальный ID из данных. Иначе при удалении элементов всё сломается.

    3. События в JSX — это не HTML
      Помните: onClick, а не onclick, и передаём функцию, а не строку.

    4. Не вешайте обработчики в render
      В вашем примере всё ок, но если вы напишете <button onClick={() => handleClick(e)}>, то при каждом рендере будет создаваться новая функция. Лучше привязывайте обработчики в конструкторе или через useCallback.


    События и списки в JSX — базовые вещи, без которых никуда. Да, сначала кажется, что это куча магии, но как только поймёте, что JSX — это просто JS, станет намного проще.

    1 ответ Последний ответ
    1
    • JspiJ Не в сети
      JspiJ Не в сети
      Jspi
      js
      написал в отредактировано Jspi
      #2

      Примеры преобразования JSX в JavaScript-объекты (Virtual DOM nodes), которые использует React.

      Базовый элемент

      // jsx
      <div>Hello World</div>
      
      // Компилируется в:
      React.createElement("div", null, "Hello World")
      
      // Результирующий объект:
      {
        type: "div",
        props: {
          children: "Hello World"
        },
        // ... другие внутренние поля React
      }
      

      Элемент с атрибутами

      // jsx
      <img src="image.jpg" alt="Example" className="photo" />
      
      // Компилируется в:
      React.createElement("img", {
        src: "image.jpg",
        alt: "Example",
        className: "photo"
      })
      
      // Результирующий объект:
      {
        type: "img",
        props: {
          src: "image.jpg",
          alt: "Example",
          className: "photo"
        }
      }
      

      Вложенные элементы

      // jsx
      <div>
        <h1>Title</h1>
        <p>Content</p>
      </div>
      
      // Компилируется в:
      React.createElement(
        "div",
        null,
        React.createElement("h1", null, "Title"),
        React.createElement("p", null, "Content")
      )
      
      // Результирующий объект:
      {
        type: "div",
        props: {
          children: [
            {
              type: "h1",
              props: { children: "Title" }
            },
            {
              type: "p",
              props: { children: "Content" }
            }
          ]
        }
      }
      

      С выражением JavaScript

      // jsx
      <div>{2 + 2}</div>
      
      // Компилируется в:
      React.createElement("div", null, 2 + 2)
      
      // Результирующий объект:
      {
        type: "div",
        props: {
          children: 4
        }
      }
      

      Компонент с пропсами

      // jsx
      <Button color="blue" size="large">
        Click me
      </Button>
      
      // Компилируется в:
      React.createElement(
        Button,
        {
          color: "blue",
          size: "large"
        },
        "Click me"
      )
      
      // Результирующий объект:
      {
        type: Button, // ссылка на функцию/класс компонента
        props: {
          color: "blue",
          size: "large",
          children: "Click me"
        }
      }
      

      Список элементов

      // jsx
      <ul>
        {items.map(item => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
      
      // Компилируется в:
      React.createElement(
        "ul",
        null,
        items.map(item => 
          React.createElement(
            "li",
            { key: item.id },
            item.name
          )
        )
      )
      
      // Результирующий объект:
      {
        type: "ul",
        props: {
          children: [
            {
              type: "li",
              key: "1",
              props: { children: "First item" }
            },
            {
              type: "li",
              key: "2",
              props: { children: "Second item" }
            }
          ]
        }
      }
      

      Фрагменты

      // jsx
      <>
        <Header />
        <MainContent />
      </>
      
      // Компилируется в:
      React.createElement(
        React.Fragment,
        null,
        React.createElement(Header, null),
        React.createElement(MainContent, null)
      )
      
      // Результирующий объект:
      {
        type: React.Fragment,
        props: {
          children: [
            { type: Header, props: {} },
            { type: MainContent, props: {} }
          ]
        }
      }
      

      Условный рендеринг

      // jsx
      <div>
        {isLoggedIn ? <UserPanel /> : <LoginButton />}
      </div>
      
      // Компилируется в:
      React.createElement(
        "div",
        null,
        isLoggedIn ? 
          React.createElement(UserPanel, null) : 
          React.createElement(LoginButton, null)
      )
      

      Как работает преобразование:

      • Babel трансформирует JSX в вызовы React.createElement()
      • React.createElement() возвращает объект описывающий элемент
      • Эти объекты образуют Virtual DOM
      • React сравнивает Virtual DOM с предыдущим состоянием и обновляет реальный DOM

      Важные особенности:

      • type может быть строкой (для HTML-элементов) или функцией/классом (для компонентов)
      • props содержат все атрибуты, включая children
      • children могут быть строкой, массивом или другим объектом
      • key и ref не попадают в props, а сохраняются отдельно
      1 ответ Последний ответ
      1
      • Алекс44А Не в сети
        Алекс44А Не в сети
        Алекс44
        написал в отредактировано
        #3

        А почему в JSX нельзя просто писать onclick как в обычном HTML? Всегда забываю про camelCase и получаю ошибки. Неужели нельзя было сделать совместимый синтаксис?

        1 ответ Последний ответ
        0
        • В Не в сети
          В Не в сети
          Ванек
          написал в отредактировано
          #4

          Это особенность JSX потому что он компилируется в JavaScript, где имена свойств чувствительны к регистру. Если бы использовали onclick, это бы не соответствовало DOM API. К тому же camelCase помогает сразу отличать встроенные события от пользовательских пропсов.

          1 ответ Последний ответ
          0
          • ВасилийВ Не в сети
            ВасилийВ Не в сети
            Василий
            написал в отредактировано
            #5

            А что насчёт передачи аргументов в обработчики? Я часто делаю onClick={handleClick(data)}, но тогда функция вызывается сразу при рендере. Как правильно?

            1 ответ Последний ответ
            0
            • WowkW Не в сети
              WowkW Не в сети
              Wowk
              написал в отредактировано
              #6

              нужно обернуть в стрелочную функцию: onClick={() => handleClick(data)}. Или использовать bind: onClick={handleClick.bind(this, data)}. Первый вариант читается проще, но создаёт новую функцию при каждом рендере.

              1 ответ Последний ответ
              0
              • Алекс44А Не в сети
                Алекс44А Не в сети
                Алекс44
                написал в отредактировано
                #7

                А есть ли разница между onClick={handleClick} и onClick={() => handleClick()}? Вроде бы работают одинаково, но первый вариант короче.

                1 ответ Последний ответ
                0
                • WowkW Не в сети
                  WowkW Не в сети
                  Wowk
                  написал в отредактировано
                  #8

                  Разница в том, что в первом случае ты передаёшь ссылку на функцию, а во втором создаёшь новую функцию-обёртку. Для производительности лучше первый вариант, если не нужно передавать аргументы. Иначе могут быть лишние ререндеры.

                  1 ответ Последний ответ
                  0

                  Категории

                  • Главная
                  • Новости
                  • Фронтенд
                  • Бекенд
                  • Языки программирования

                  Контакты

                  • Сотрудничество
                  • info@exlends.com
                  • Наш чат
                  • Наш ТГ канал

                  © 2024 - 2025 ExLends, Inc. Все права защищены.

                  Политика конфиденциальности
                  • Войти

                  • Нет учётной записи? Зарегистрироваться

                  • Войдите или зарегистрируйтесь для поиска.
                  • Первое сообщение
                    Последнее сообщение
                  0
                  • Лента
                  • Категории
                  • Последние
                  • Метки
                  • Популярные
                  • Пользователи
                  • Группы