使用useRef反应将组件滚动到视图中

时间:2020-10-03 19:45:33

标签: reactjs

我正在尝试在导航栏中获取onclick处理程序,以将不同的组件滚动到视图中。 我找到了一种可行的方法,但是我从反应中得到了警告,并且代码看起来不是很干净。我希望有人知道如何以更正确的方式解决此问题,从而消除警告并保持代码干净。

我将在每个组件上创建一个scrollTo,因此在Header.js中将几乎进行类似的调用,只是使用不同的名称。

这是应用程序的结构:

App.js

const App = () => {
    return (
        <div>
            <Header />
            <Banner />
            <About />
            <Technology />
            <Contact />
            <Portfolio />
        </div>
    );
};

Technology.js

const Technology = () => {
    return (
        <section className="technology">
            <div className="heading white">
                <h2>Technologies</h2>
                <p>Some techno</p>
            </div>
        </section>
    )
   }

Header.js(导航栏)

const Header = () => {
    let technology;

useEffect(() => {
        technology = document.querySelector(".technology");
    }, []);

    return (
        <header>
            <p className="logo">Portfolio</p>
            <div className="toggle"></div>
            <ul>
                <li>
                    <p onClick={() => window.scrollTo({ top: 0, behavior: "smooth" })}>
                        Home
                    </p>
                </li>
                <li>
                    <p>About Me</p>
                </li>
                <li>
                    <p onClick={() => technology.scrollIntoView({ behavior: "smooth" })}>
                        Technologies
                    </p>
                </li>
                <li>
                    <p>Contact</p>
                </li>
                <li>
                    <p>Projects</p>
                </li>
            </ul>
        </header>
    );
};

这是警告:

从React Hook内部分配给'technology'变量 每次渲染后useEffect将丢失。保留价值 时间,将其存储在useRef Hook中,并将可变值保留在 “ .current”属性。否则,您可以直接移动此变量 内部useEffect

要解决此问题,我想我需要将其从App.js传递到Header.js,并将其从每个组件传递到App.js?不幸的是,我的谷歌搜索技能不足以解决这个问题。

我知道在react中有一个用于此的库,但是我现在希望以一种更“原生”的方式解决这个问题。

2 个答案:

答案 0 :(得分:1)

您可以使用函数ref灵活地执行此操作,这将允许元素将自身注册到通用ref对象上。引用绝对是必经之路。您希望避免在使用React时尽可能直接访问DOM。

const { useRef } = React;

function App() {
  const pageRefs = useRef({});

  return (
    <div className="app">
      <Header pageRefs={pageRefs} />
      <About pageRefs={pageRefs} />
      <Technology pageRefs={pageRefs} />
      <Portfolio pageRefs={pageRefs} />
    </div>
  );
};

function Header({ pageRefs }) {

  function scrollIntoView(type) {
    pageRefs.current[type].scrollIntoView({ behavior: "smooth" });
  };

  return (
    <header>
      <button onClick={() => scrollIntoView('about')}>
        About
      </button>
      <button onClick={() => scrollIntoView('techno')}>
        Technology
      </button>
      <button onClick={() => scrollIntoView('portfolio')}>
        Portfolio
      </button>
    </header>
  );
};

function About({ pageRefs }) {
  return (
    <section
      className="page about"
      ref={el => pageRefs.current = { ...pageRefs.current, about: el }}>
      About
    </section>
  );
};

function Technology({ pageRefs }) {
  return (
    <section
      className="page techno"
      ref={el => pageRefs.current = { ...pageRefs.current, techno: el }}>
      Technology
    </section>
  );
};

function Portfolio({ pageRefs }) {
  return (
    <section
      className="page portfolio"
      ref={el => pageRefs.current = { ...pageRefs.current, portfolio: el }}>
      Portfolio
    </section>
  );
};

ReactDOM.render(<App />, document.getElementById('root'));
* {
  padding: 0;
  margin: 0;
}

.app {
  width: 100%;
}

.page {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}

.about {
  background-color: crimson;
}

.techno {
  background-color: lemonchiffon;
}

.portfolio {
  background-color: cornflowerblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>

答案 1 :(得分:0)

您可以为此使用回调。

export const scrollIntoView = (selector, option) => (event) => {
  const el = document.querySelector(selector);

  if (!el) return;

  el.scrollIntoView(option);
};

用法。

import { scrollIntoView } from 'path/to/file';

const scrollIntoViewTechnology = scrollIntoView('.technology', { behavior: "smooth" });

const Component = () => {
  return (
    <button type='button' onClick={scrollIntoViewTechnology}>Lorem Ipsum</button>
  );
};