简体   繁体   English

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

[英]Scrolling components into view with react with useRef

I'm trying to get the onclick handlers in my navbar to scroll different components into view.我试图让我的导航栏中的 onclick 处理程序将不同的组件滚动到视图中。 I have found a way that works, but I'm getting a warning from react, as well as the code is not looking very clean.我找到了一种有效的方法,但是我收到了来自 react 的警告,而且代码看起来不太干净。 I'm hoping someone knows how to solve this is in a more correct way, so that the warning goes away and also keeps the code clean.我希望有人知道如何以更正确的方式解决这个问题,这样警告就会消失并保持代码干净。

I'm going to create a scrollTo on each component, so in the Header.js there will be almost similar calls, with different names only.我将在每个组件上创建一个 scrollTo,因此在 Header.js 中将有几乎相似的调用,只是名称不同。

Here is the structure of the app:这是应用程序的结构:

App.js应用程序.js

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

Technology.js技术.js

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

Header.js (Navbar) 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>
    );
};

Here is the warning:这是警告:

Assignments to the 'technology' variable from inside React Hook useEffect will be lost after each render.每次渲染后,React Hook useEffect 内部对“技术”变量的分配将丢失。 To preserve the value over time, store it in a useRef Hook and keep the mutable value in the '.current' property.要随着时间的推移保留该值,请将其存储在 useRef Hook 中,并将可变值保留在 '.current' 属性中。 Otherwise, you can move this variable directly inside useEffect否则,您可以直接在 useEffect 中移动此变量

To solve this I guess I need to pass it from App.js to Header.js, and get it from each Component to App.js?为了解决这个问题,我想我需要将它从 App.js 传递到 Header.js,并将它从每个组件传递到 App.js? My googling skills have not been sufficient in solving this unfortunately.不幸的是,我的谷歌搜索技能不足以解决这个问题。

I know there is a library for this in react, but I was hoping to solve this in a more "native" way for now.我知道在 React 中有一个用于此的库,但我现在希望以更“本机”的方式解决这个问题。

You can do this quite flexibly with function refs, which will allow elements to register themselves onto a universal ref object.您可以使用函数 refs 非常灵活地做到这一点,这将允许元素将自己注册到通用ref对象上。 Refs are definitely the way to go;参考绝对是要走的路; you want to avoid accessing the DOM directly whenever possible when using React.在使用 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>

You can use callback for this.您可以为此使用回调。

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

  if (!el) return;

  el.scrollIntoView(option);
};

Usage.用法。

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

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

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM