mergeProps для объединения пропсов

В библиотеке React Aria функция mergeProps служит для безопасного объединения нескольких объектов пропсов в один, обеспечивая корректное слияние обработчиков событий и атрибутов элементов. Это особенно важно при создании доступных компонентов, где одни пропсы могут добавляться внутренними хуками библиотеки, а другие — напрямую разработчиком.


Основная концепция

mergeProps(...propsList) принимает любое количество объектов пропсов и возвращает единый объект, который можно передать элементу JSX. Основная задача — избежать перезаписи обработчиков событий и атрибутов, чтобы компоненты корректно реагировали на пользовательские действия и сохраняли доступность.

Пример базового использования:

import { mergeProps } from '@react-aria/utils';

const buttonPropsFromHook = {
  onClick: () => console.log('hook click'),
  'aria-label': 'Кнопка'
};

const customButtonProps = {
  onClick: () => console.log('custom click'),
  className: 'btn-primary'
};

const mergedProps = mergeProps(buttonPropsFromHook, customButtonProps);

/*
mergedProps =
{
  onClick: [Function that calls both handlers],
  'aria-label': 'Кнопка',
  className: 'btn-primary'
}
*/

В этом примере оба обработчика onClick будут вызваны последовательно при нажатии на кнопку, а атрибут aria-label сохранится без конфликтов.


Как mergeProps объединяет обработчики событий

Функция mergeProps умеет объединять:

  • События мыши: onClick, onMouseEnter, onMouseLeave
  • События клавиатуры: onKeyDown, onKeyUp, onKeyPress
  • Фокус-события: onFocus, onBlur
  • Другие стандартные события DOM

При объединении нескольких функций обработчика mergeProps создает цепочку вызовов, где каждый обработчик вызывается в порядке передачи пропсов, сохраняя контекст this и аргументы события.

Пример объединения событий клавиатуры:

const props1 = {
  onKeyDown: e => console.log('props1 key down')
};

const props2 = {
  onKeyDown: e => console.log('props2 key down')
};

const merged = mergeProps(props1, props2);

<button {...merged}>Нажми меня</button>

// Нажатие клавиши вызовет:
// props1 key down
// props2 key down

Объединение атрибутов элементов

mergeProps также объединяет атрибуты элементов, такие как id, aria-* и className. Поведение при совпадении атрибутов зависит от типа:

  • className: объединяется через пробел, что позволяет сохранять все стили
  • style: объединяются объекты стилей, свойства из последнего объекта имеют приоритет
  • aria-* и другие стандартные атрибуты: берется значение из первого объекта, если нет конфликта

Пример объединения классов и стилей:

const propsA = { className: 'btn', style: { color: 'red' } };
const propsB = { className: 'large', style: { backgroundColor: 'blue' } };

const merged = mergeProps(propsA, propsB);

/*
merged =
{
  className: 'btn large',
  style: { color: 'red', backgroundColor: 'blue' }
}
*/

Практическое применение в React Aria

На практике mergeProps часто используется при интеграции хуков React Aria, таких как useButton, useCheckbox или useTextField. Эти хуки возвращают пропсы, обеспечивающие доступность, а разработчик добавляет свои кастомные свойства.

Пример с кнопкой:

import { useButton } from '@react-aria/button';
import { mergeProps } from '@react-aria/utils';

function AccessibleButton(props) {
  const ref = React.useRef();
  const { buttonProps } = useButton(props, ref);

  const customProps = {
    className: 'btn-primary',
    onClick: () => console.log('Кастомное действие')
  };

  return <button {...mergeProps(buttonProps, customProps)} ref={ref}>
    {props.children}
  </button>;
}

Здесь:

  1. useButton добавляет обработчики фокуса, клавиатуры и aria-атрибуты.
  2. Пользовательские пропсы добавляют стили и свой обработчик onClick.
  3. mergeProps объединяет всё в единый объект, сохраняя корректную работу как библиотеки, так и кастомного кода.

Важные нюансы

  1. Порядок аргументов Порядок, в котором передаются объекты в mergeProps, влияет на приоритет атрибутов и порядок вызова обработчиков. Первый объект считается базовым, последующие добавляют новые или объединяют обработчики.

  2. Не изменяет исходные объекты mergeProps возвращает новый объект, оригинальные пропсы остаются неизменными, что предотвращает неожиданные побочные эффекты.

  3. Совместимость с React Объединение функций через mergeProps полностью безопасно для React — не нарушает ререндеринг и не создает лишние вызовы.

  4. Рекомендуется для доступных компонентов Любой компонент, использующий хуки React Aria, должен применять mergeProps, чтобы не ломать встроенную доступность при добавлении пользовательских обработчиков или атрибутов.


Заключение по использованию

mergeProps является ключевым инструментом при работе с React Aria. Он обеспечивает:

  • Безопасное объединение обработчиков событий
  • Слияние атрибутов элементов без конфликтов
  • Поддержку доступности и предсказуемое поведение компонентов

Это делает библиотеку гибкой для кастомизации, сохраняя стандарты WAI-ARIA и предотвращая баги, связанные с перезаписью пропсов.