javascript - 如何在不重新渲染随机放置的同级组件数组的情况下,根据滚动位置更新样式化组件的样式?

标签 javascript reactjs react-hooks styled-components

我有一个执行这些操作的简单组件:

  1. 使用钩子(Hook),设置状态以跟踪 window.scrollY
  2. 附上 scroll事件监听窗口以更新状态
  3. 创建一个包含 10 个样式组件的数组 - 每个组件都有一个随机分配的 absolute职位
  4. 返回/呈现 10 个点另一个样式组件 - 一个三 Angular 形,其高度使用步骤 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组件高度重新计算/重新渲染。最初渲染的点不会更新或改变。<​​/p>

我的问题

正如您可能猜到的那样,每个滚动事件都会重新呈现这些点,这不仅对性能来说很糟糕,而且会导致每个滚动事件中的点都有一个新的随机位置。

我的问题

  1. 我怎样才能得到 Triangle使用更新的 scroll 重新渲染值,但没有 Dot组件重新渲染?
  2. 更多的是次要问题:如果我还想更新 Dot 中的某些样式滚动组件(例如颜色),但更新随机 topleft在初始 Mount 上创建的位置,我该怎么做?

我可以用 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);

Working demo

或者通过使用回调函数来初始化状态

// 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>
  );
};

Working demo

关于javascript - 如何在不重新渲染随机放置的同级组件数组的情况下,根据滚动位置更新样式化组件的样式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57917250/

相关文章:

javascript - 本地服务 filepicker.io JS

javascript - 如何在 html 和 css 中创建多色圆圈

reactjs - 如何将 this.state.songs 更新到歌曲列表

javascript - 使用 Hooks 和标签更新 React 状态

javascript - Bootstrap 模式联系表单问题

javascript - 在Bower中找到冲突的包,找到合适的包安装

javascript - React/Javascript - 如何将收到的数据过滤到已过滤的列列表?

reactjs - 如何在样式组件中使用 "hover"(CSS) 操作?

reactjs - 在 react 中使用 useParams Hook

reactjs - react Hook : Component is not rendering in Nested Routing