Изменения React useRef не вызвали перезапуск компонента, который зависит от ref.current

#reactjs

#reactjs

Вопрос:

Целью этого компонента Upsell является отображение чего-либо в определенной области (портал). Поэтому он будет принимать элемент DOM и createPortal от этого. Проблема в том, что widgetDom всегда имеет значение null и приводит к тому, что createPortal не получил возможности для рендеринга.

В consumer я использую useRef и передаю widgetRef.current компонент Upsell. Я ожидаю, что при widgetRef подключении реального элемента widgetRef.current изменения приведут к повторному обновлению компонента, но этого не происходит.

Можете ли вы взглянуть на следующий код или песочницу? Спасибо!

 const Upsell: React.FC<{ widgetDom: HTMLElement | null }> = ({ widgetDom }) => {
  return (
    <div className="box">
      <h1>Order Summary</h1>
      {widgetDom amp;amp; createPortal(<h2>Order Summary Widget</h2>, widgetDom)}
    </div>
  );
};

export default function App() {
  const widgetDom = React.useRef<HTMLElement | null>(null);
  return (
    <div className="App">
      <div className="box" style={{ width: "60%" }}>
        <div className="box">
          <h1>Ad Selection</h1>
        </div>
        <Upsell widgetDom={widgetDom.current} />
      </div>
      <div className="box" style={{ width: "40%" }}>
        <div id="orderSummaryWidget" ref={widgetDom} className="box"></div>
      </div>
    </div>
  );
}

  

Ответ №1:

Ссылки по дизайну не вызывают повторной визуализации при их изменении:

Имейте в виду, что useRef не уведомляет вас об изменении его содержимого. Изменение свойства .current не приводит к повторному отображению. Если вы хотите запустить некоторый код, когда React присоединяет или отсоединяет ссылку к DOM-узлу, вы можете вместо этого использовать ссылку обратного вызова.

Самое простое решение — использовать state вместо ref:

 export default function App() {
  const [widgetDom, setWidgetDom] = useState<HTMLElement | null>(null);

  return (
    <div className="App">
      <div className="box" style={{ width: "60%" }}>
        <div className="box">
          <h1>Ad Selection</h1>
        </div>
        <Upsell widgetDom={widgetDom} />
      </div>
      <div className="box" style={{ width: "40%" }}>
        <div id="orderSummaryWidget" ref={setWidgetDom} className="box"></div>
      </div>
    </div>
  );
}