<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Синтаксис JSX: списки и события]]></title><description><![CDATA[<h2>JSX — это не XML, а просто сахар</h2>
<p dir="auto">JSX — это синтаксический сахар над <code>React.createElement()</code>, который позволяет писать HTML-подобный код прямо в JavaScript. И как по мне я его очень люблю, а с приходом <strong>Next.js</strong> так вообще работать с React одно удовольствие.</p>
<p dir="auto">Да: <code>&lt;div&gt;Привет, JSX&lt;/div&gt;</code> — это валидный JS. Но не будем спешить радоваться: здесь есть свои подводные камни, особенно когда речь заходит о событиях и списках. Их разбирали уже много сотен раз, но я хочу поделиться своими мыслями и показать конкретные примеры.</p>
<hr />
<p dir="auto">В отличие от нативного HTML, где мы пишете <code>onclick</code>, в JSX события пишутся в <code>camelCase</code> и передаются как функции, а не строки. То есть не <code>onClick="handleClick()"</code>, а <code>onClick={handleClick}</code>. Обратим внимание на фигурные скобки и отсутствие кавычек — это не HTML!</p>
<h2>handleKeyUp</h2>
<pre><code class="language-jsx">function handleKeyUp(e) {
  document.getElementById('title').innerText = e.target.value;
}
</code></pre>
<p dir="auto"><strong>Что происходит</strong>: Каждый раз, когда вы отпускаете клавишу в инпуте, функция лезет в DOM через <code>document.getElementById</code> и меняет текст элемента с <code>id="title"</code>.</p>
<p dir="auto"><strong>Как применяется</strong>:</p>
<pre><code class="language-jsx">&lt;input onKeyUp={handleKeyUp} type="text" /&gt;
</code></pre>
<p dir="auto"><strong>Почему так делать НЕ НАДО</strong>:<br />
В React никогда не трогайте DOM напрямую (ну, кроме крайних случаев). Это как писать <code>var</code> вместо <code>const</code> — технически работает, но коллеги будут плакать. В реальности вы бы использовали <code>useState</code> и обновляли состояние.</p>
<p dir="auto">Но для примера сойдёт.</p>
<hr />
<h2>handleClick</h2>
<pre><code class="language-jsx">function handleClick(e) {
  document.getElementById('title').innerText += ' ' + e.target.textContent;
}
</code></pre>
<p dir="auto"><strong>Что происходит</strong>: При клике на кнопку к тексту заголовка добавляется пробел и текст самой кнопки (в нашем случае —: Строка).</p>
<p dir="auto"><strong>Как применяется</strong>:</p>
<pre><code class="language-jsx">&lt;button onClick={handleClick}&gt;Строка&lt;/button&gt;
</code></pre>
<p dir="auto"><strong>Лайфхак</strong>: Обратите внимание, что <code>e.target.textContent</code> — это содержимое кнопки. Так что если мы напишем <code>&lt;button&gt;Клик!&lt;/button&gt;</code>, в заголовок добавится “Клик!”.</p>
<hr />
<h2>handleMouseEnter / handleMouseLeave</h2>
<pre><code class="language-jsx">function handleMouseEnter(e) {
  e.target.classList.add('hover');
}

function handleMouseLeave(e) {
  e.target.classList.remove('hover');
}
</code></pre>
<p dir="auto"><strong>Что происходит</strong>: При наведении курсора на кнопку добавляется класс <code>hover</code>, при уходе — удаляется. В CSS вы бы прописали стили для <code>.hover</code>, чтобы кнопка светилась, как неоновая вывеска.</p>
<p dir="auto"><strong>Как применяется</strong>:</p>
<pre><code class="language-jsx">&lt;button 
  onMouseEnter={handleMouseEnter}
  onMouseLeave={handleMouseLeave}
&gt;
  Кнопка
&lt;/button&gt;
</code></pre>
<p dir="auto"><strong>Для чего это нужно</strong>: Hover-эффекты — must-have для любого уважающего себя UI. Без них кнопки будут выглядеть как серые кирпичи.</p>
<hr />
<h2>handleMouseDown / handleMouseUp</h2>
<pre><code class="language-jsx">function handleMouseDown(e) {
  e.target.classList.add('active');
}

function handleMouseUp(e) {
  e.target.classList.remove('active');
}
</code></pre>
<p dir="auto"><strong>Что происходит</strong>: При нажатии кнопки (но не отпускании!) добавляется класс <code>active</code>. Это нужно, чтобы кнопка “проваливалась” при клике — стандартный паттерн для UX.</p>
<p dir="auto"><strong>Как применяется</strong>:</p>
<pre><code class="language-jsx">&lt;button
  onMouseDown={handleMouseDown}
  onMouseUp={handleMouseUp}
&gt;
  Кнопка
&lt;/button&gt;
</code></pre>
<p dir="auto"><strong>Важно</strong>: Не путайте <code>onClick</code> и <code>onMouseDown</code>! <code>onClick</code> сработает при отпускании кнопки мыши, а <code>onMouseDown</code> — при нажатии. Если нужно имитировать нажатие, как в реальной жизни — юзайте <code>onMouseDown</code>/<code>onMouseUp</code>.</p>
<hr />
<h2>Списки в JSX: map() — ваш новый лучший друг</h2>
<p dir="auto">Ну что с событиями мы вроде разобрались теперь самое время перейти к спискам, хотя их бы стоило перенести в отдельную тему, но я все же напишу здесь.</p>
<p dir="auto">Теперь про <strong>списки</strong>. В вашем коде три одинаковых кнопки с разными строками. Писать их вручную — как пилить воду топором. В React списки рендерятся через <code>map()</code>, а каждому элементу нужно задать ключ <code>(key)</code>, чтобы React не тормозил.</p>
<pre><code class="language-jsx">const emojis = ['Строка', 'Строка1', 'Строка2'];

ReactDOM.render((
  &lt;div&gt;
    &lt;input onKeyUp={handleKeyUp} type="text" /&gt;
    {emojis.map((emoji, index) =&gt; (
      &lt;button
        key={index}
        onMouseEnter={handleMouseEnter}
        onClick={handleClick}
        onMouseLeave={handleMouseLeave}
        onMouseDown={handleMouseDown}
        onMouseUp={handleMouseUp}
      &gt;
        {emoji}
      &lt;/button&gt;
    ))}
  &lt;/div&gt;
), document.querySelector('#root'));
</code></pre>
<p dir="auto"><strong>Что изменилось</strong>:</p>
<ul>
<li>Создали массив эмодзи.</li>
<li>Проитерировались через <code>map()</code>.</li>
<li>Добавили <code>key={index}</code> — без этого React будет ругаться в консоли (и правильно делает).</li>
</ul>
<p dir="auto">Почему <code>key</code> обязателен?<br />
React использует ключи для отслеживания изменений в списке. Если вы уберёте <code>key</code>, при обновлении списка React будет перерисовывать всё подряд, а не только изменённые элементы. Это как пытаться найти иголку в стоге сена без метки.</p>
<hr />
<h2>Частые ошибки новичков</h2>
<ol>
<li>
<p dir="auto">Не трогайте DOM напрямую<br />
Вместо <code>document.getElementById</code> юзайте <code>useState</code> и рефы (<code>useRef</code>). Иначе вы превратите React-приложение в jQuery-халтуру.</p>
</li>
<li>
<p dir="auto">Всегда задавайте <code>key</code> в списках<br />
И лучше не индекс (<code>index</code>), а уникальный ID из данных. Иначе при удалении элементов всё сломается.</p>
</li>
<li>
<p dir="auto">События в JSX — это не HTML<br />
Помните: <code>onClick</code>, а не <code>onclick</code>, и передаём функцию, а не строку.</p>
</li>
<li>
<p dir="auto">Не вешайте обработчики в <code>render</code><br />
В вашем примере всё ок, но если вы напишете <code>&lt;button onClick={() =&gt; handleClick(e)}&gt;</code>, то при каждом рендере будет создаваться новая функция. Лучше привязывайте обработчики в конструкторе или через <code>useCallback</code>.</p>
</li>
</ol>
<hr />
<p dir="auto">События и списки в JSX — базовые вещи, без которых никуда. Да, сначала кажется, что это куча магии, но как только поймёте, что JSX — это просто JS, станет намного проще.</p>
]]></description><link>https://forum.exlends.ru/topic/228/sintaksis-jsx-spiski-i-sobytiya</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 07:27:24 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/228.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 29 Aug 2025 10:18:33 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 19:00:52 GMT]]></title><description><![CDATA[<p dir="auto">Разница в том, что в первом случае ты передаёшь ссылку на функцию, а во втором создаёшь новую функцию-обёртку. Для производительности лучше первый вариант, если не нужно передавать аргументы. Иначе могут быть лишние ререндеры.</p>
]]></description><link>https://forum.exlends.ru/post/509</link><guid isPermaLink="true">https://forum.exlends.ru/post/509</guid><dc:creator><![CDATA[Wowk]]></dc:creator><pubDate>Fri, 05 Sep 2025 19:00:52 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 19:00:31 GMT]]></title><description><![CDATA[<p dir="auto">А есть ли разница между onClick={handleClick} и onClick={() =&gt; handleClick()}? Вроде бы работают одинаково, но первый вариант короче.</p>
]]></description><link>https://forum.exlends.ru/post/508</link><guid isPermaLink="true">https://forum.exlends.ru/post/508</guid><dc:creator><![CDATA[Алекс44]]></dc:creator><pubDate>Fri, 05 Sep 2025 19:00:31 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 18:58:39 GMT]]></title><description><![CDATA[<p dir="auto">нужно обернуть в стрелочную функцию: onClick={() =&gt; handleClick(data)}. Или использовать bind: onClick={handleClick.bind(this, data)}. Первый вариант читается проще, но создаёт новую функцию при каждом рендере.</p>
]]></description><link>https://forum.exlends.ru/post/507</link><guid isPermaLink="true">https://forum.exlends.ru/post/507</guid><dc:creator><![CDATA[Wowk]]></dc:creator><pubDate>Fri, 05 Sep 2025 18:58:39 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 18:58:35 GMT]]></title><description><![CDATA[<p dir="auto">А что насчёт передачи аргументов в обработчики? Я часто делаю onClick={handleClick(data)}, но тогда функция вызывается сразу при рендере. Как правильно?</p>
]]></description><link>https://forum.exlends.ru/post/506</link><guid isPermaLink="true">https://forum.exlends.ru/post/506</guid><dc:creator><![CDATA[Василий]]></dc:creator><pubDate>Fri, 05 Sep 2025 18:58:35 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 18:58:32 GMT]]></title><description><![CDATA[<p dir="auto">Это особенность JSX потому что он компилируется в JavaScript, где имена свойств чувствительны к регистру. Если бы использовали onclick, это бы не соответствовало DOM API. К тому же camelCase помогает сразу отличать встроенные события от пользовательских пропсов.</p>
]]></description><link>https://forum.exlends.ru/post/505</link><guid isPermaLink="true">https://forum.exlends.ru/post/505</guid><dc:creator><![CDATA[Ванек]]></dc:creator><pubDate>Fri, 05 Sep 2025 18:58:32 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Fri, 05 Sep 2025 18:58:29 GMT]]></title><description><![CDATA[<p dir="auto">А почему в JSX нельзя просто писать onclick как в обычном HTML? Всегда забываю про camelCase и получаю ошибки. Неужели нельзя было сделать совместимый синтаксис?</p>
]]></description><link>https://forum.exlends.ru/post/504</link><guid isPermaLink="true">https://forum.exlends.ru/post/504</guid><dc:creator><![CDATA[Алекс44]]></dc:creator><pubDate>Fri, 05 Sep 2025 18:58:29 GMT</pubDate></item><item><title><![CDATA[Reply to Синтаксис JSX: списки и события on Mon, 01 Sep 2025 08:02:51 GMT]]></title><description><![CDATA[<h2>Примеры преобразования JSX в JavaScript-объекты (Virtual DOM nodes), которые использует React.</h2>
<p dir="auto">Базовый элемент</p>
<pre><code class="language-jsx">// jsx
&lt;div&gt;Hello World&lt;/div&gt;

// Компилируется в:
React.createElement("div", null, "Hello World")

// Результирующий объект:
{
  type: "div",
  props: {
    children: "Hello World"
  },
  // ... другие внутренние поля React
}
</code></pre>
<p dir="auto">Элемент с атрибутами</p>
<pre><code class="language-jsx">// jsx
&lt;img src="image.jpg" alt="Example" className="photo" /&gt;

// Компилируется в:
React.createElement("img", {
  src: "image.jpg",
  alt: "Example",
  className: "photo"
})

// Результирующий объект:
{
  type: "img",
  props: {
    src: "image.jpg",
    alt: "Example",
    className: "photo"
  }
}
</code></pre>
<p dir="auto">Вложенные элементы</p>
<pre><code class="language-jsx">// jsx
&lt;div&gt;
  &lt;h1&gt;Title&lt;/h1&gt;
  &lt;p&gt;Content&lt;/p&gt;
&lt;/div&gt;

// Компилируется в:
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" }
      }
    ]
  }
}
</code></pre>
<p dir="auto">С выражением JavaScript</p>
<pre><code class="language-jsx">// jsx
&lt;div&gt;{2 + 2}&lt;/div&gt;

// Компилируется в:
React.createElement("div", null, 2 + 2)

// Результирующий объект:
{
  type: "div",
  props: {
    children: 4
  }
}
</code></pre>
<p dir="auto">Компонент с пропсами</p>
<pre><code class="language-jsx">// jsx
&lt;Button color="blue" size="large"&gt;
  Click me
&lt;/Button&gt;

// Компилируется в:
React.createElement(
  Button,
  {
    color: "blue",
    size: "large"
  },
  "Click me"
)

// Результирующий объект:
{
  type: Button, // ссылка на функцию/класс компонента
  props: {
    color: "blue",
    size: "large",
    children: "Click me"
  }
}
</code></pre>
<p dir="auto">Список элементов</p>
<pre><code class="language-jsx">// jsx
&lt;ul&gt;
  {items.map(item =&gt; (
    &lt;li key={item.id}&gt;{item.name}&lt;/li&gt;
  ))}
&lt;/ul&gt;

// Компилируется в:
React.createElement(
  "ul",
  null,
  items.map(item =&gt; 
    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" }
      }
    ]
  }
}
</code></pre>
<p dir="auto">Фрагменты</p>
<pre><code class="language-jsx">// jsx
&lt;&gt;
  &lt;Header /&gt;
  &lt;MainContent /&gt;
&lt;/&gt;

// Компилируется в:
React.createElement(
  React.Fragment,
  null,
  React.createElement(Header, null),
  React.createElement(MainContent, null)
)

// Результирующий объект:
{
  type: React.Fragment,
  props: {
    children: [
      { type: Header, props: {} },
      { type: MainContent, props: {} }
    ]
  }
}
</code></pre>
<p dir="auto">Условный рендеринг</p>
<pre><code class="language-jsx">// jsx
&lt;div&gt;
  {isLoggedIn ? &lt;UserPanel /&gt; : &lt;LoginButton /&gt;}
&lt;/div&gt;

// Компилируется в:
React.createElement(
  "div",
  null,
  isLoggedIn ? 
    React.createElement(UserPanel, null) : 
    React.createElement(LoginButton, null)
)
</code></pre>
<h2>Как работает преобразование:</h2>
<ul>
<li>Babel трансформирует JSX в вызовы  React.createElement()</li>
<li>React.createElement() возвращает объект описывающий элемент</li>
<li>Эти объекты образуют Virtual DOM</li>
<li>React сравнивает Virtual DOM с предыдущим состоянием и обновляет реальный DOM</li>
</ul>
<h3>Важные особенности:</h3>
<ul>
<li>type может быть строкой (для HTML-элементов) или функцией/классом (для компонентов)</li>
<li>props содержат все атрибуты, включая children</li>
<li>children могут быть строкой, массивом или другим объектом</li>
<li>key и ref не попадают в props, а сохраняются отдельно</li>
</ul>
]]></description><link>https://forum.exlends.ru/post/412</link><guid isPermaLink="true">https://forum.exlends.ru/post/412</guid><dc:creator><![CDATA[Aladdin]]></dc:creator><pubDate>Mon, 01 Sep 2025 08:02:51 GMT</pubDate></item></channel></rss>