Подписка scroll в теле App создаётся на каждом рендере и никогда не удаляется. Для прилипающей панели обычно достаточно position: sticky; счётчик обновляйте функционально, повторяющиеся Item создайте из списка.
Переписать и оптимизировать React‑компоненты
Подписка scroll в теле App создаётся на каждом рендере и никогда не удаляется. Для прилипающей панели обычно достаточно position: sticky; счётчик обновляйте функционально, повторяющиеся Item создайте из списка.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Выполнить рефакторинг представленного кода, устранив прямое взаимодействие с DOM и улучшив структуру компонентов.
App.tsx
import React, { useState } from "react";
import "./styles.css";
import Item from "./Item";
export default function App() {
const [count, setCount] = useState(0);
window.addEventListener("scroll", () => {
const { scrollY } = window;
if (scrollY > 100) {
const topSection = document.querySelector<HTMLDivElement>(".top-section");
if (topSection) {
topSection.style.position = "absolute";
topSection.style.top = scrollY + "px";
} else {
return;
}
} else {
const topSection = document.querySelector<HTMLDivElement>(".top-section");
if (topSection) {
topSection.style.position = "static";
} else {
return;
}
}
});
return (
<div className="App">
<div className="block-wrapper">
<div className="top-section">
<button
onClick={() => {
alert(count);
}}
>
Show count
</button>
<button
onClick={() => {
setCount(0);
}}
>
Reset count
</button>
</div>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
<Item
onAdd={() => {
setCount(count + 1);
}}
/>
</div>
</div>
);
}
Item.tsx
import React from "react";
import "./styles.css";
type Props = {
onAdd: () => void;
};
export default function Item(props: Props) {
return (
<div className="block">
<button className="btn" onClick={props.onAdd}>
Add to cart
</button>
</div>
);
}
Ответ
Подписка scroll в теле App создаётся на каждом рендере и никогда не удаляется. Для прилипающей панели обычно достаточно position: sticky; счётчик обновляйте функционально, повторяющиеся Item создайте из списка.
.top-section { position: sticky; top: 0; z-index: 1; background: white; }
Удалите весь window.addEventListener из тела компонента. В App:
const onAdd = React.useCallback(() => setCount(value => value + 1), []);
// В JSX вместо шести одинаковых блоков:
{Array.from({ length: 6 }, (_, index) => <Item key={index} onAdd={onAdd} />)}
Sticky ограничен своим контейнером и начинает прилипать при достижении края, не обязательно после глобальных 100px прокрутки. Если нужен именно этот порог, храните window.scrollY > 100 в состоянии через эффект с cleanup и меняйте CSS-класс декларативно. memo(Item) имеет смысл только при подтверждённой стоимости рендера и стабильных props.