React Router 重定向哈希链接

9

我为我的网站导航栏创建了一个自定义按钮组件。当用户点击按钮时,该组件返回一个重定向,将用户带到所选页面。

export default class Button extends Component {
    constructor(props){
        super(props);
        this.state = {redirect:false};
        this._handleClick = this._handleClick.bind(this);
    }

    _handleClick(e) {
        e.stopPropagation();
        this.setState({redirect: true});
    }

    componentDidUpdate() {
        if (this.state.redirect){
            this.setState({redirect:false});
            this.props.onRedirect();
        }
    }

    render() {
        if (this.state.redirect){
            return <Redirect push to={this.props.dest}/>;
        }
        else {
            return (
                <li className="button" onClick={this._handleClick}>
                    <h5>{this.props.text}</h5>
                </li>
            );
        }
    }
}

现在,我想添加与同一页不同部分相对应的按钮。我所知道的最简单的方法是使用哈希链接。一个例子是按钮将重定向到以下地址:
/home#description

然而,React Router 并没有原生支持此功能。我查看了许多添加此功能的包,例如 react-router-hash-linkreact-scrollchor。但是,这些都无法与重定向一起使用,而是依赖于 Link 或自定义组件。
我该如何在按钮中添加此功能?
7个回答

2
你可以更新window.location.href,因为它不会触发页面刷新。
例如:
window.location.href = '#your-anchor-tag';

2

谁说React Router不支持这个功能! 你不需要那些包。你可以通过重定向哈希来实现,我会给你一个使用React-Router Route的例子。

<Route
  exact
  path="/signup"
  render={props => {
    if (props.location.hash === "#foo")
      return <Redirect push to="signup#bar"
    return <Signup />
  }}
/>

现在我想起来,你的版本可能不支持此功能,但如果这有所帮助,请告诉我 :) 愉快编码!

/signup#foo should redirect to /signup#bar - Alex Dunlop

2
我能想到的一个解决方案是使用HOCshooks。最终结果如下:
  • 您将使应用程序滚动到指定位置......
  • 无需真正创建自定义按钮/链接......
  • 而且不需要对现有屏幕(例如:HomeScreen)进行太多更改
  • 额外加分:用户可以复制、共享和使用URL,这将自动滚动到所需的部分


在假设以下代码是伪代码的情况下(它们基于我所知道的内容,并未经过测试),并假设存在一个HomeScreen组件,我将尝试将添加到

<Switch>
  <Route to='/home/:section' component={HomeScreen} />
  <Route to='/home' component={HomeScreen} />
</Switch>

然后:
function withScrollToTarget(WrappedComponent) {
  class WithScroll extends React.Component {
    componentDidMount() {
      const { match: { params: { section } } } = this.props
      // Remember we had 2 <Route/>s, so if `section` is provided...
      if (section) {
        const scrollToTarget = document.getElementById(section)
        // And just in case the item was removed or there was an ID mismatch
        if (scrollToTarget) { scrollToTarget.scrollIntoView() }
      }
    }
    render() { return <WrappedComponent {...this.props} /> }
  }
  return WithScroll
}

function useScrollToTarget(section) {
  useEffect(() => {
    if (section) {
      const scrollToTarget = document.getElementById(section)
      if (scrollToTarget) { scrollToTarget.scrollIntoView() }
    }
  }, [section])
}

用法:
<nav>
  <Link to='/home'>{'Home'}</Link>
  <Link to='/home/description'>{'Description'}</Link>
</nav>


class HomeScreen extends React.Component { /* ... */ }
export default withScrollToTarget(HomeScreen)
// or
function HomeScreen() {
  const { params: { section } } = useMatch() // from react-router-dom
  useScrollTotarget(section)
  return (
    <div>
      <h1 id='introduction'>Introduction</h1>
      <h1 id='description'>Description</h1>
    </div>
  )
}

TLDR:
  • '/home/:section'的路由必须在'/home'上面。如果相反,每次当<Switch/>将当前URL与to进行比较时,它会在到达'/home'时评估为true,并永远不会到达'/home/:section'
  • scrollIntoView()是一个合法的函数
  • 如果这对你有用,你应该了解如何在HOC中转发refs和提升静态内容

0

React-hash-link 应该适用于您的重定向用例。

您可以将 <HashLinkObserver /> 添加到组件树中,它将侦听哈希链接并相应地滚动,而不是依赖于 Link 或自定义组件。


0

我正在尝试解决一个类似但略有不同的问题,我想废弃旧的哈希路由,采用新的路由。这里的帖子帮助我找到了最终的解决方案:

<Route
    exact
    path={'/thing/:id'}
    render={({
        match: {
            params: { id },
        },
    }) => (
        <Redirect
            push
            to={`/newThing/${id}`}
        />
    )}
/>

0
我认为你应该使用react-router-dom。
yarn add react-router-dom

现在像这样更新自定义按钮组件

import React from 'react';
import { withRouter } from "react-router-dom";
class Button extends Component {
    constructor(props){
        super(props);
        this.state = {redirect:false};
        this._handleClick = this._handleClick.bind(this);
    }

    _handleClick(e) {
        e.stopPropagation();
        this.setState({redirect: true});
    }

    componentDidUpdate() {
        if (this.state.redirect){
            this.setState({redirect:false});
            //this.props.onRedirect();
            this.props.history.push('new uri');
        }
    }

    render() {
        if (this.state.redirect){
            return <Redirect push to={this.props.dest}/>;
        }
        else {
            return (
                <li className="button" onClick={this._handleClick}>
                    <h5>{this.props.text}</h5>
                </li>
            );
        }
    }
}
export default withRouter(Button);

-1

我面临了同样的问题,我已经创建了一个HOC来处理哈希重定向,您可以按照以下步骤实现哈希重定向

  1. 创建HOC并将下面的代码添加到其中

文件名:hashComponent

import React, { useEffect } from 'react';

export default function hashComponent(WrappedComponent) {

  return function () {
    const { pathname, hash }=window.location;
    useEffect(() => {

      if(hash)
        window.location.href=`${pathname}${hash}`;
    }, [hash])

    return <WrappedComponent />
  }
}
  1. 在你想要处理哈希 URL 的组件中导入你的 HOC

  2. 然后在导出你的组件时添加以下代码:

    export default hashComponent(YourComponentName)


无法工作:React Hook“useEffect”不能在回调函数中调用。React Hooks必须在React函数组件或自定义React Hook函数中调用 - douglasrcjames

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接