在单独的路线中使用useRef反应滚动导航

时间:2020-04-17 17:14:43

标签: javascript reactjs typescript react-router

关于我的最后一个问题here,我一直在尝试将裁判映射到其他路线。滚动处理程序正在运行,但是ref.currentnull。所以我正在寻找这个难题的答案。使用没有外部依赖项,如何解决此问题?

App.tsx

import React, { useEffect, useRef } from "react";
import { BrowserRouter, Route, NavLink, useLocation } from "react-router-dom";
import Home from "./pages/Home";
import "./styles.css";

const Header = ({ refs }) => {
  const location = useLocation();

  useEffect(() => {
    console.log("location", location.pathname);
    switch (location.pathname) {
      case "/about":
        scrollSmoothHandler(refs.aboutRef);
        break;
      case "/contact":
        scrollSmoothHandler(refs.contactRef);
        break;
      case "/hero":
        scrollSmoothHandler(refs.heroRef);
        break;

      default:
        scrollSmoothHandler(refs.homeRef);
        break;
    }
  }, [location, refs]);

  const scrollSmoothHandler = ref => {
    console.log("Triggered.");
    console.log(ref.current);
    //ref.current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <>
      <NavLink to="/hero" activeClassName="selected">
        Hero
      </NavLink>
      <NavLink to="/about" activeClassName="selected">
        About
      </NavLink>
      <NavLink to="/contact" activeClassName="selected">
        Contact
      </NavLink>
    </>
  );
};

function App() {
  const homeRef = useRef(null);
  const heroRef = useRef(null);
  const aboutRef = useRef(null);
  const contactRef = useRef(null);

  return (
    <div ref={homeRef} className="App">
      <BrowserRouter>
        <Header refs={{ aboutRef, contactRef, heroRef, homeRef }} />
        <Route
          exact
          to="/"
          refs={{ aboutRef, contactRef, heroRef, homeRef }}
          component={Home}
        />
        // More routes here.
      </BrowserRouter>
    </div>
  );
}

export default App;

Home.tsx

import React, { Fragment, forwardRef, useRef } from "react";
import "../styles.css";

const Hero = forwardRef((props, ref) => {
  return (
    <section ref={ref}>
      <h1>Hero Section</h1>
    </section>
  );
});

const About = forwardRef((props, ref) => {
  return (
    <section ref={ref}>
      <h1>About Section</h1>
    </section>
  );
});

const Contact = forwardRef((props, ref) => {
  return (
    <section ref={ref}>
      <h1>Contact Section</h1>
    </section>
  );
});

function Home(refs) {
  const heroRef = useRef(refs.heroRef);
  const aboutRef = useRef(refs.aboutRef);
  const contactRef = useRef(refs.contactRef);
  return (
    <Fragment>
      <Hero ref={heroRef} />
      <About ref={aboutRef} />
      <Contact ref={contactRef} />
    </Fragment>
  );
}

export default Home;

您可以找到指向我的代码沙箱的链接:here。叉子非常感谢。

1 个答案:

答案 0 :(得分:1)

如果不在组件上使用forwardRef,则不能将ref作为props传递给名称为prop的其他组件。您需要为其分配另一个名称,以便它起作用,例如innerRefs。

还要将ref作为prop传递给Route组件,请使用render prop方法

App.tsx

npm rebuild node-sass

Home.tsx

import React, { useEffect, useRef } from "react";
import { BrowserRouter, Route, NavLink, useLocation } from "react-router-dom";
import Home from "./pages/Home";
import "./styles.css";

const Header = ({ innerRefs }) => {
  const location = useLocation();

  useEffect(() => {
    console.log("location", location.pathname);
    switch (location.pathname) {
      case "/about":
        scrollSmoothHandler(innerRefs.aboutRef);
        break;
      case "/contact":
        scrollSmoothHandler(innerRefs.contactRef);
        break;
      case "/hero":
        scrollSmoothHandler(innerRefs.heroRef);
        break;

      default:
        scrollSmoothHandler(innerRefs.homeRef);
        break;
    }
  }, [location, innerRefs]);

  const scrollSmoothHandler = innerRef => {
    console.log("Triggered.");
    console.log(innerRef.current);
    innerRef.current.scrollIntoView({ behavior: "smooth" });
  };

  return (
    <>
      <NavLink to="/hero" activeClassName="selected">
        Hero
      </NavLink>
      <NavLink to="/about" activeClassName="selected">
        About
      </NavLink>
      <NavLink to="/contact" activeClassName="selected">
        Contact
      </NavLink>
    </>
  );
};

function App() {
  const homeRef = useRef(null);
  const heroRef = useRef(null);
  const aboutRef = useRef(null);
  const contactRef = useRef(null);

  return (
    <div ref={homeRef} className="App">
      <BrowserRouter>
        <Header innerRefs={{ aboutRef, contactRef, heroRef, homeRef }} />
        <Route
          exact
          to="/"
          render={routeProps => (
            <Home
              {...routeProps}
              innerRefs={{ aboutRef, contactRef, heroRef, homeRef }}
            />
          )}
        />
        // More routes here.
      </BrowserRouter>
    </div>
  );
}

export default App;

Working demo here