← Назад к вопросам

Как использовать 1 widget на странице 2 раза?

2.0 Middle🔥 111 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как использовать один компонент дважды на странице

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

1. Базовый пример - простое переиспользование

Наиболее простой способ - просто отрендерить компонент дважды:

// Компонент Button
function Button({ label, onClick }) {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
}

// Страница - используем компонент 2 раза
function HomePage() {
  const handleClick1 = () => console.log('Button 1 clicked');
  const handleClick2 = () => console.log('Button 2 clicked');

  return (
    <div>
      <Button label="Start" onClick={handleClick1} />
      <Button label="Stop" onClick={handleClick2} />
    </div>
  );
}

Компонент Button отрендерится 2 раза с разными props. Это работает потому что компонент не имеет внутреннего состояния.

2. Компоненты с состоянием - важно использовать ключи

Если компонент имеет состояние (useState), при рендеринге дважды состояние будет ОБЩИМ!

// Компонент с состоянием
function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

// НЕПРАВИЛЬНО - состояния будут синхронизированы
function BadPage() {
  return (
    <div>
      <Counter /> {/* Счетчик 1 */}
      <Counter /> {/* Счетчик 2 - ОДИН counter.js для обоих! */}
    </div>
  );
}

// Если нажать + в первом, увеличится И во втором!
// Это потому что React не знает, что это разные экземпляры

3. Решение: используйте key prop

Добавьте уникальный ключ, чтобы React различал экземпляры:

// ПРАВИЛЬНО - с уникальными ключами
function GoodPage() {
  return (
    <div>
      <div key="counter-1">
        <h3>Counter 1</h3>
        <Counter />
      </div>
      <div key="counter-2">
        <h3>Counter 2</h3>
        <Counter />
      </div>
    </div>
  );
}

// Или более явно с wrapper
function CounterWithTitle({ title }) {
  return (
    <div>
      <h3>{title}</h3>
      <Counter />
    </div>
  );
}

function BestPage() {
  return (
    <div>
      <CounterWithTitle key="c1" title="First Counter" />
      <CounterWithTitle key="c2" title="Second Counter" />
    </div>
  );
}

4. Динамическое рендеринг компонента (в цикле)

Для отрендеринга компонента много раз используйте map:

function UserCard({ name, email }) {
  return (
    <div className="card">
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}

function UserList() {
  const users = [
    { id: 1, name: 'Alice', email: 'alice@example.com' },
    { id: 2, name: 'Bob', email: 'bob@example.com' },
    { id: 3, name: 'Charlie', email: 'charlie@example.com' }
  ];

  return (
    <div>
      {users.map(user => (
        // ВАЖНО: используйте уникальный key, обычно ID
        <UserCard key={user.id} name={user.name} email={user.email} />
      ))}
    </div>
  );
}

5. Компонент внутри другого компонента - правильный способ

Частая ошибка - создавать компонент внутри функции. Это приводит к потере состояния:

// НЕПРАВИЛЬНО - компонент создается заново при каждом рендере
function BadParent() {
  function ChildComponent() {
    return <div>Child</div>;
  }

  return (
    <div>
      <ChildComponent /> {/* Создается каждый раз */}
      <ChildComponent /> {/* Это разные экземпляры */}
    </div>
  );
}

// ПРАВИЛЬНО - определите компонент ВНЕ функции
function ChildComponent() {
  return <div>Child</div>;
}

function GoodParent() {
  return (
    <div>
      <ChildComponent /> {/* Один и тот же компонент */}
      <ChildComponent /> {/* Используется дважды */}
    </div>
  );
}

6. Условный рендеринг компонента несколько раз

function Dashboard({ showMetrics = true }) {
  return (
    <div>
      <h1>Dashboard</h1>
      
      {/* Рендеринг один раз в основной контент */}
      <MetricsWidget title="Overview" />
      
      {/* Условно рендеринг дважды */}
      {showMetrics && (
        <>
          <MetricsWidget title="By Day" />
          <MetricsWidget title="By Month" />
        </>
      )}
    </div>
  );
}

7. Modal/Popup на странице несколько раз

Частый кейс - модальные окна:

function Modal({ isOpen, title, onClose }) {
  if (!isOpen) return null;
  return (
    <div className="modal">
      <div className="modal-content">
        <h2>{title}</h2>
        <button onClick={onClose}>Close</button>
      </div>
    </div>
  );
}

function Page() {
  const [openModal1, setOpenModal1] = useState(false);
  const [openModal2, setOpenModal2] = useState(false);

  return (
    <div>
      <button onClick={() => setOpenModal1(true)}>Open Modal 1</button>
      <button onClick={() => setOpenModal2(true)}>Open Modal 2</button>

      {/* Один и тот же компонент используется дважды с разным состоянием */}
      <Modal
        key="modal-1"
        isOpen={openModal1}
        title="First Modal"
        onClose={() => setOpenModal1(false)}
      />
      <Modal
        key="modal-2"
        isOpen={openModal2}
        title="Second Modal"
        onClose={() => setOpenModal2(false)}
      />
    </div>
  );
}

8. Общие данные между двумя экземплярами компонента

Если компонентам нужны общие данные, поднимите состояние выше:

function Counter({ value, onIncrement }) {
  return (
    <div>
      <p>Count: {value}</p>
      <button onClick={onIncrement}>+</button>
    </div>
  );
}

function TwoCounters() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <h2>Shared Count: {count}</h2>
      
      {/* Оба счетчика используют одно состояние */}
      <Counter value={count} onIncrement={() => setCount(count + 1)} />
      <Counter value={count} onIncrement={() => setCount(count + 1)} />
    </div>
  );
}

Ключевые правила

  1. Простые компоненты (без состояния) - рендерьте столько раз, сколько нужно
  2. Компоненты с состоянием - используйте уникальные key
  3. В циклах ВСЕГДА используйте key (обычно ID из данных)
  4. Определяйте компоненты ВНЕ других функций
  5. Используйте key='string' для статического контента (всегда один и тот же)
  6. Поднимайте состояние вверх, если компонентам нужны общие данные
  7. Не создавайте компоненты внутри render-функций - они будут пересоздаваться

Правильное использование key и структурирование компонентов позволит вам без проблем переиспользовать один компонент столько раз, сколько нужно.