javascript - 如何在不重新渲染随机放置的同级组件数组的情况下根据滚动位置更新样式组件的样式?
问题描述
我有一个执行这些操作的简单组件:
- 使用钩子,设置状态以跟踪
window.scrollY
- 将
scroll
eventListener 附加到窗口以更新状态 - 创建一个包含 10 个样式组件的数组 - 每个组件都有一个随机分配的
absolute
位置 - 返回/渲染 10 个点和另一个样式组件 - 一个三角形,其高度是使用步骤 1 中定义的滚动状态计算的。
const App = () => {
// state to keep track of how many px scrolled
const [scroll, setScroll] = useState(window.scrollY);
const handleScroll = () => setScroll(window.scrollY);
// set up listener on window to update scroll state on scroll
useEffect(() => {
window.addEventListener("scroll", handleScroll);
}, []);
// create 10 dots with random positions
const dots = [];
for (let x = 0; x < 10; x++) {
dots.push(
<Dot
key={x}
topValue={getRandomIntInclusive(1, 199)}
leftValue={getRandomIntInclusive(1, 99)}
/>
);
}
return (
<div className="App">
{dots}
<Triangle heightValue={scroll / 10} />
</div>
);
};
我想要发生的事情
当我向下滚动时,我唯一想要发生的是Triangle
组件高度重新计算/重新渲染。最初渲染的点不会更新或改变。
我的问题
正如您可能猜到的那样,每个滚动事件都会重新渲染这些点,这不仅会降低性能,而且会导致每个滚动事件中的点都有一个新的随机位置。
我的问题
- 如何
Triangle
使用更新的scroll
值重新渲染,但不让Dot
组件重新渲染? - 更多的次要问题:如果我还想更新
Dot
滚动组件中的某些样式(例如颜色),但不更新在初始安装上创建的随机top
和left
位置,我该怎么做?
我可以用 vanilla JS 很容易地完成这样的事情,但我不太清楚 React 的方式。
此问题的完整工作沙箱:https ://codesandbox.io/embed/hopeful-greider-jb3td
解决方案
您需要做的是计算一次点位置并将其保存在一个数组中,以便在滚动位置更改时不会在每次渲染时重新计算它们
您可以使用useEffect
空deps
数组来执行此操作
// main component
const App = () => {
// state to keep track of how many px scrolled
const [scroll, setScroll] = useState(window.scrollY);
const handleScroll = () => setScroll(window.scrollY);
const [posArr, setPos] = useState([]);
useEffect(() => {
const pos = [];
for (let x = 0; x < 10; x++) {
pos.push({ topValue: getRandomIntInclusive(1, 199), leftValue: getRandomIntInclusive(1, 99)})
}
setPos(pos);
}, [])
// set up listener on window to update scroll state on scroll
useEffect(() => {
window.addEventListener("scroll", handleScroll);
}, []);
// create 10 dots with random positions
const dots = [];
for (let x = 0; x < 10; x++) {
dots.push(
<Dot
key={x}
topValue={posArr[x] && posArr[x].topValue}
leftValue={posArr[x] && posArr[x].leftValue}
/>
);
}
return (
<div className="App">
<br />
<h2>Scroll to make triangle grow</h2>
<br />
<h4>Ideally, the dots would not rerender on scroll</h4>
<Debug>Px scrolled: {scroll}</Debug>
{dots}
<Triangle heightValue={scroll / 10} />
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
或使用回调函数初始化状态到 useState
// main component
const App = () => {
// state to keep track of how many px scrolled
const [scroll, setScroll] = useState(window.scrollY);
const handleScroll = () => setScroll(window.scrollY);
// set up listener on window to update scroll state on scroll
useEffect(() => {
window.addEventListener("scroll", handleScroll);
}, []);
const [posArr, setPos] = useState(() => {
const pos = [];
for (let x = 0; x < 10; x++) {
pos.push({ topValue: getRandomIntInclusive(1, 199), leftValue: getRandomIntInclusive(1, 99) })
}
return pos;
});
// create 10 dots with random positions
const dots = [];
for (let x = 0; x < 10; x++) {
dots.push(
<Dot
key={x}
topValue={posArr[x].topValue}
leftValue={posArr[x].leftValue}
/>
);
}
return (
<div className="App">
<br />
<h2>Scroll to make triangle grow</h2>
<br />
<h4>Ideally, the dots would not rerender on scroll</h4>
<Debug>Px scrolled: {scroll}</Debug>
{dots}
<Triangle heightValue={scroll / 10} />
</div>
);
};
推荐阅读
- excel - 混淆条件格式
- html - 谷歌表单提交后添加加载html页面
- amazon-web-services - AWS IoT Core - 在同一设备中同时使用标准双向 MQTT 连接和基本摄取 MQTT 连接
- python - 计算批量订单的价格 - 请求公式/计算帮助
- ssl - 无法从另一台机器通过 https 访问 mitmproxy
- python - PyCharm 找不到任何东西
- python - find_all() 没有返回值
- javascript - React window.pageYOffset 在滚动时保持为零
- excel - 我可以在主工作表上插入和删除行以更新工作簿中的其他工作表吗?
- python - 为什么我会收到“错误:需要以下参数:wsi_fn”