【问题标题】:How to intercept back button in a React SPA using function components and React Router v5如何使用功能组件和 React Router v5 拦截 React SPA 中的后退按钮
【发布时间】:2020-09-08 08:52:14
【问题描述】:

我在 React 的 SPA 中工作,它不使用 React Router 来创建任何路由;我不需要允许用户导航到特定页面。 (想想多页问卷,按顺序填写。)

但是,当用户按下浏览器上的返回按钮时,我不希望他们退出整个应用程序;我希望能够在用户按下后退按钮时触发一个功能,该按钮只是将页面呈现为他们最后一次选择之前的状态。 (每个页面都是一个组件,它们组装在一个数组中,由currentPage 状态变量(来自状态挂钩)跟踪,所以我可以简单地渲染pages[currentPage -1]

使用(如有必要)当前版本的 React Router (v5)、函数组件和 Typescript,我如何访问后退按钮事件以禁用它并用我自己的函数替换它?

(我发现的其他答案要么使用类组件、特定于旧版本 React Router 的函数,要么使用特定框架,如 Next.js。)

任何和所有的见解都是值得赞赏的。

【问题讨论】:

    标签: reactjs typescript react-router single-page-application


    【解决方案1】:

    经过太多小时的工作,我找到了解决方案。因为一旦我找到了正确的路径,最终并没有那么困难,我发布了我的解决方案,希望它可以节省其他人的时间。

    1. 为 Web 安装 React Router,并键入 - npm install --save react-router-dom @types/react-router-dom
    2. react-router-dom 导入{ BrowserRouter, Route, RouteComponentProps, withRouter }
    3. 标识按下后退按钮时其状态将发生变化的组件。
    4. 通过解构从RouteComponentProps 传入history
      function MyComponent( { history }: ReactComponentProps) {
          ...
      }
      
    5. 屏幕状态改变(用户认为是新页面)添加一个空白条目到history;例如:

      function MyComponent( { history }: ReactComponentProps) {
      
          const handleClick() {
              history.push('')
          }
      
      }
      

      这会在历史记录中创建一个空白条目,因此历史记录具有后退按钮可以访问的条目;但用户看到的 url 不会改变。

    6. 处理按下浏览器上的后退按钮时应发生的更改。 (请注意,组件生命周期方法,如 componentDidMount,在函数组件中不起作用。确保从 react 导入 useEffect。)
      useEffect(() => {
          // code here would fire when the page loads, equivalent to `componentDidMount`.
          return () => {
              // code after the return is equivalent to `componentWillUnmount`
              if (history.action === "POP") {
                  // handle any state changes necessary to set the screen display back one page.
              }
          }
      })
      
    7. 将其包装在withRouter 中并创建一个可以访问路由属性的新组件:
      const ComponentWithHistory = withRouter(MyComponent);
      
    8. 现在将其全部包装在 <BrowserRouter /><Route /> 中,以便 React Router 将其识别为路由器,并将所有路径路由到 path="/",这将捕获所有路由,除非指定了具有更具体路径的路由 (由于history.push(""),无论如何这一切都是一样的;历史看起来像["", "", "", "", ""])。

      function App() {
      
      return (
          <BrowserRouter>
              <Route path="/">
                  <ThemeProvider theme={theme}>
                      <ComponentWithHistory />
                  </ThemeProvider>
              </Route>
          </BrowserRouter>
          );
      }
      
      export default App;
      
    9. 一个完整的例子现在看起来像这样:

      function MyComponent( { history }: ReactComponentProps) {
          // use a state hook to manage a "page" state variable
          const [page, setPage] = React.useState(0)
      
      
          const handleClick() {
              setPage(page + 1);
              history.push('');
          }
      
          useEffect(() => {
          return () => {
              if (history.action === "POP") {
                  // set state back one to render previous "page" (state)
                  setPage(page - 1)
              }
          }
       })
      }
      
      const ComponentWithHistory = withRouter(MyComponent);
      
      function App() {
      
          return (
              <BrowserRouter>
                  <Route path="/">
                      <ThemeProvider theme={theme}>
                          <ComponentWithHistory />
                      </ThemeProvider>
                  </Route>
              </BrowserRouter>
              );
          }
      
      export default App;
      

    如果有更好的方法,我很想听听;但这对我来说效果很好。

    【讨论】:

      猜你喜欢
      • 2017-01-13
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多