简体   繁体   English

为什么在使用 react-router 时必须手动刷新页面才能加载组件?

[英]Why do I have to manually refresh the page for the component to load when using react-router?

在此处输入图像描述 I have a React application that uses react-router-dom to load different components from the sidebar.我有一个 React 应用程序,它使用 react-router-dom 从侧边栏加载不同的组件。 Whenever I click the link in the sidebar, the URL changes, but I must manually refresh the page to get the actual content of the page to load.每当我单击侧边栏中的链接时,URL 都会发生变化,但我必须手动刷新页面以获取要加载的页面的实际内容。

I want my application to automatically refresh the page when a sidebar link is clicked instead of the user having to manually refresh the page in order for a component to load.我希望我的应用程序在单击侧边栏链接时自动刷新页面,而不是用户必须手动刷新页面才能加载组件。

function App() {
  const [locale, setLocale] = useState('en');

  return (
    <>
      <Routes>
        <Route path="/" element={<IntlProvider locale={locale}><Layout setLocale={setLocale} /></IntlProvider>}>
          <Route index element={<Home />} />
          <Route path="experience" element={<Experience />} />
          <Route path="skills" element={<Skills />} />
          <Route path="portfolio" element={<Portfolio />} />
          <Route path="contact" element={<Contact />} />
        </Route>
      </Routes>
    </>

  );
}

export default App;

This is my App.js这是我的 App.js

const Sidebar = ({ toggled, handleToggleSidebar }) => {
  const intl = useIntl();
  return (
    <ProSidebar
      toggled={toggled}
      breakPoint="md"
      onToggle={handleToggleSidebar}
    >
      <SidebarHeader>
        <div
          style={{
            padding: '24px',
            textTransform: 'uppercase',
            fontWeight: 'bold',
            fontSize: 14,
            letterSpacing: '1px',
            overflow: 'hidden',
            textOverflow: 'ellipsis',
            whiteSpace: 'nowrap',
          }}
        >
          <Link style={{ display: 'block', padding: '15px 0' }} to="/">
            <img style={{ display: 'block', margin: '-3em 3em', width: '133px', height: 'auto' }} src={LogoS} alt="Logo" />
          </Link>
        </div>
      </SidebarHeader>

      <SidebarContent>
        <Menu iconShape="circle">

          <MenuItem icon={<FaHome size={32} />}>
            {intl.formatMessage({ id: 'Home' })}
            <NavLink activeclassname="active" to="/"></NavLink>
          </MenuItem>

          <MenuItem icon={<FaProjectDiagram size={32} />}>
            {intl.formatMessage({ id: 'Experience' })}
            <NavLink to="/experience"></NavLink>
          </MenuItem>

          <MenuItem icon={<FaToolbox size={32} />}>
            {intl.formatMessage({ id: 'Skills' })}
            <NavLink to="/skills"></NavLink>
          </MenuItem>

          <MenuItem icon={<FaFolderOpen size={32} />}>
            {intl.formatMessage({ id: 'Portfolio' })}
            <NavLink to="/portfolio"></NavLink>
          </MenuItem>

          <MenuItem icon={<FaTelegramPlane size={32} />}>
            {intl.formatMessage({ id: 'Contact' })}
            <NavLink to="/contact"></NavLink>
          </MenuItem>

        </Menu>
      </SidebarContent>
    </ProSidebar >
  );
};

export default Sidebar;

This is my Sidebar.js这是我的 Sidebar.js

function Layout({ setLocale }) {
  const [rtl, setRtl] = useState(false);
  const [collapsed, setCollapsed] = useState(false);
  const [image, setImage] = useState(true);
  const [toggled, setToggled] = useState(false);

  const handleCollapsedChange = (checked) => {
    setCollapsed(checked);
  };

  const handleRtlChange = (checked) => {
    setRtl(checked);
    setLocale(checked ? 'ar' : 'en');
  };
  const handleImageChange = (checked) => {
    setImage(checked);
  };

  const handleToggleSidebar = (value) => {
    setToggled(value);
  };

  return (
    <div className={`app ${rtl ? 'rtl' : ''} ${toggled ? 'toggled' : ''}`}>
      <Sidebar
        image={image}
        collapsed={collapsed}
        rtl={rtl}
        toggled={toggled}
        handleToggleSidebar={handleToggleSidebar}
      />
      <Main
        image={image}
        toggled={toggled}
        collapsed={collapsed}
        rtl={rtl}
        handleToggleSidebar={handleToggleSidebar}
        handleCollapsedChange={handleCollapsedChange}
        handleRtlChange={handleRtlChange}
        handleImageChange={handleImageChange}
      />
      <Outlet />
    </div>
  );
}

export default Layout;

This is the Layout.js that renders the page.这是呈现页面的 Layout.js。

const Contact = () => {
  const [letterClass, setLetterClass] = useState('text-animate')
  const form = useRef()

  useEffect(() => {
    return setTimeout(() => {
      setLetterClass('text-animate-hover')
    }, 3000)
  }, [])

  const sendEmail = (e) => {
    e.preventDefault()

    emailjs
      .sendForm(
        'service_v8uv1al',
        'template_xge6tgj',
        form.current,
        'UuX3z3S-mWAnAL7BY')
      .then(
        () => {
          alert('Message successfully sent!')
          window.location.reload(false)
        },
        () => {
          alert('Failed to send the message, please try again')
        }
      )
  }

  return (
    <>
      <div className="container contact-page">
        <div className="text-zone">
          <h1>
            <AnimatedLetters
              letterClass={letterClass}
              strArray={['C', 'o', 'n', 't', 'a', 'c', 't', ' ', 'm', 'e']}
              idx={15}
            />
          </h1>
          <div className='app_footer-cards'>
            <div className='app_footer-card'>
              <img src={emailLogo} alt="email" />
              <a href="mailto:k.maumau11@gmail.com" className='p-text'>k.maumau0@gmail.com</a>
            </div>
            <div className='app_footer-card'>
              <img src={phoneLogo} alt="mobile" />
              <a href="tel: +1 (832) 764-9796" className='p-text'>+1 (832) 764-9796</a>
            </div>
          </div>
          <p>
            If you have a request or question, or simply just want to
            say Hello don't hesitate to contact me using the form below!
          </p>
          <div className="contact-form">
            <form ref={form} onSubmit={sendEmail}>
              <ul>
                <li className="half">
                  <input placeholder="Name" type="text" name="name" required />
                </li>
                <li className="half">
                  <input
                    placeholder="Email"
                    type="email"
                    name="email"
                    required
                  />
                </li>
                <li>
                  <input
                    placeholder="Subject"
                    type="text"
                    name="subject"
                    required
                  />
                </li>
                <li>
                  <textarea
                    placeholder="Message"
                    name="message"
                    required
                  ></textarea>
                </li>
                <li>
                  <input type="submit" className="flat-button" value="SEND" />
                </li>
              </ul>
            </form>
          </div>
        </div>
      </div>
      <Loader type="ball-scale" />
    </>
  )
}

export default Contact

Contact Page Code联系页面代码

Issue问题

Your app code is actually crashing when navigating away from a page.离开页面时,您的应用程序代码实际上正在崩溃。 It's not clear why you aren't seeing the React error page ( perhaps you are running a production build ) but the issue is that for each page you are using a useEffect hook to set a timeout to update some local state.目前尚不清楚为什么您没有看到 React 错误页面(也许您正在运行生产构建),但问题是对于每个页面,您都使用useEffect挂钩来设置超时以更新某些本地状态。

useEffect(() => {
  return setTimeout(() => {
    setLetterClass('text-animate-hover');
  }, 3000);
}, []);

The issue with this is that React assumes that anything returned from the useEffect hook is a cleanup function to be invoked when the component is rerendering/unmounting.问题在于 React 假定从useEffect挂钩返回的任何内容都是在组件重新渲染/卸载时调用的清理函数。 setTimeout returns a number representing the timer id. setTimeout返回一个表示计时器 ID 的数字。

Reloading the page is effectively reloading the entire app on the current URL path.重新加载页面实际上是在当前 URL 路径上重新加载整个应用程序。

Solution解决方案

On each of these pages, refactor the logic to return a cleanup function that clears the timeout.在每个页面上,重构逻辑以返回清除超时的清理函数。

useEffect(() => {
  const timer = setTimeout(() => {
    setLetterClass('text-animate-hover');
  }, 3000);
  return () => clearTimeout(timer);
}, []);

This allows the timeout to be instantiated when the component mounts, and for the offhand chance the user navigates away from the page and this component unmounts, it will clear the timeout and won't invoke the callback that will enqueue a state state.这允许在组件安装时实例化超时,并且对于用户导航离开页面并且该组件卸载的偶然机会,它将清除超时并且不会调用将使状态状态排队的回调。

Suggestion建议

It seems that each of these pages has the same animation letterClass state for the AnimatedLetters component.对于AnimatedLetters组件,这些页面中的每一个似乎都具有相同的动画letterClass状态。 Instead of duplicating the same code/logic across all pages, abstract it into a custom React hook that returns the letterClass value.与其在所有页面上复制相同的代码/逻辑,不如将其抽象为一个自定义的 React 钩子,该钩子返回letterClass值。

Example:例子:

const useLetterClass = ({
  start = 'text-animate',
  end = 'text-animate-hover'
}) => {
  const [letterClass, setLetterClass] = useState(start);

  useEffect(() => {
    const timer = setTimeout(() => {
      setLetterClass(end);
    }, 3000);
    return () => clearTimeout(timer);
  }, []);

  return { letterClass };
};

In each page component import the useLetterClass hook, call, and pass the returned letterClass prop value.在每个页面组件中导入useLetterClass挂钩,调用并传递返回的letterClass值。

Example:例子:

const Contact = () => {
  const { letterClass } = useLetterClass({
    start: 'text-animate',
    end: 'text-animate-hover',
  });
  const form = useRef();

  const sendEmail = (e) => {
    ...
  }

  return (
    <>
      <div className="container contact-page">
        <div className="text-zone">
          <h1>
            <AnimatedLetters
              letterClass={letterClass}
              strArray={['C', 'o', 'n', 't', 'a', 'c', 't', ' ', 'm', 'e']}
              idx={15}
            />
          </h1>
          ...
        </div>
      </div>
      <Loader type="ball-scale" />
    </>
  );
};

编辑Why-do-i-have-to-manually-refresh-the-page-for-the-component-to-load-when-using

The sandbox code you provided also seems to have an issue with some of the SCSS, specifically with a $sidebar-color variable missing.您提供的沙箱代码似乎也有一些SCSS 的问题,特别是缺少$sidebar-color变量。 I'm not familiar with SCSS much, but I don't suspect it is related to the routing/navigation issue I described above.我对 SCSS 不太熟悉,但我不怀疑它与我上面描述的路由/导航问题有关。

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

相关问题 使用react-router选择新项目时刷新组件 - Refresh component when new item selected using react-router 使用 react-router 时,我刷新并丢失状态? - When using react-router, I refresh and lose my state? 为什么在 react-router-dom 中使用 Link 和 Switch 时需要刷新页面? - Why do I need to refresh the page when using Link and Switch with react-router-dom? 反应路由器 | 仅在页面刷新时加载组件 - React Router | load component only on page refresh 在React.js的父组件中使用react-router时,如何使用react context API将数据从父组件传递到子组件? - How do I use react context API to pass data from parent component to child component when using react-router in the parent component in React.js? 使用 react-router 滚动到同一页面上的组件 - Scrolling to a component on the same page using react-router 单击react-router Link时,如何将状态传输到父组件? - How do I transmit a state to a parent component when clicking a react-router Link? 向前刷新或手动输入时不加载反应路由器内容 - React Router content not load when refresh forward or manually input 如何使用 react-router 的链接组件链接到我的应用程序外部的 URL? - How do I link to a URL outside of my app using the Link component of react-router? 反应路由器会影响页面加载时间吗? - Will react-router affect page load time?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM