如何在不重新加载整个页面的情况下进行路由?

28

我正在使用react-route,并且在路由方面遇到了一些问题。

整个页面重新加载,导致我已经获取并存储在reducer中的所有数据每次都要重新加载。

这是我的路由文件:

var CustomRoute = React.createClass({
    render:function(){
        return <Router history={browserHistory}>
            <Route path="/" component={Layout}>
                <IndexRedirect to="/landing" />
                <Route path="landing" component={Landing} />
                <Route path="login" component={Login} />
                <Route path="form" component={Form} />
                <Route path="*" component={NoMatch} />
            </Route>
        </Router>
    },
});

在路由之前,我已经通过调用main.jsx中的操作存储了数据。

/** @jsx React.DOM */
'use strict'
var ReactDOM = require('react-dom')
var React = require('react')
var Index = require('./components/index')
var createStore = require("redux").createStore
var applyMiddleware = require("redux").applyMiddleware
var Provider = require("react-redux").Provider
var thunkMiddleware = require("redux-thunk").default
var reducer = require("./reducers")
var injectTapEventPlugin =require('react-tap-event-plugin');
injectTapEventPlugin()
var createStoreWithMiddleware=applyMiddleware(thunkMiddleware)(createStore);
var store=createStoreWithMiddleware(reducer);
store.dispatch(actions.load_contacts()) //////////// <<<<<< this is what i call to store data already

ReactDOM.render( <Provider store={store}><Index/></Provider> , document.getElementById('content'))

问题是,如果成功登录,我必须路由到另一个页面:

this.props.dispatch(actions.login(this.state.login,this.state.password,(err)=>{
    this.setState({err:err})
    if (!err){
        window.location = "/form"
    }
}));  

window.location可以实现路由跳转,但会重新加载所有内容,效率较低。对于手动路由,我使用<Link\>来在不重新加载页面的情况下进行路由跳转,但对于自动化路由,我不确定该如何处理。

非常感谢任何建议。

6个回答

15

对于最新版本(v2.0.0-rc5),推荐的导航方法是直接将其推入历史记录单例。

示例

相关代码

import { browserHistory } from './react-router'
browserHistory.push('/some/path')
如果使用较新的react-router API,当在组件内部时,需要利用来自this.propshistory,因此:
static propTypes = {
    history: React.PropTypes.object
}

this.props.history.push('/some/path');
如果使用 react-router-redux,它提供了一个可以调度的 push 函数,可以这样使用:
import { push } from 'react-router-redux';
this.props.dispatch(push('/some/path'));

v2.4.0版本开始,可以使用高阶组件将路由作为组件的属性进行获取。

import { withRouter } from 'react-router'

class Example extends React.Component {
   // use `this.props.router.push('/some/path')` here
};

// Export the decorated class
var DecoratedExample = withRouter(Example);

// PropTypes

Example.propTypes = {
  router: React.PropTypes.shape({
    push: React.PropTypes.func.isRequired
  }).isRequired
};

访问此链接以获取更多信息:http://kechengpuzi.com/q/s31079081


3
非常感谢,这对我很有帮助。 只需导入 var browserHistory = require('react-router').browserHistory, 并调用 browserHistory.push('/form') 即可。 - Sijan Shrestha
我做了这个,但整个页面仍在刷新。 - Manuel Hernandez
1
示例链接已失效(404)。更多信息链接也无法访问。您能更新此答案吗? - Nestor Solalinde

15

React >= 16.8和react-router v4

没有人提到使用钩子的解决方案。自React 16.8以来(和react-router 4,不确定是最小版本,我使用最新版本),您可以使用一个名为useHistory的钩子。

import { useHistory } from 'react-router';

const MyHookComponent: React.FC = () => {
    
    const routerHistory = useHistory();
    routerHistory.push('/page-where-to-redirect');

    return <></>;
}

export default MyHookComponent;

更多信息请参见 https://reactrouter.com/web/api/Hooks/

更新:react-router v6

在 react-router 6 中引入了一个新的钩子:

import { useNavigate } from "react-router-dom";

const navigate = useNavigate();

navigate('/page-where-to-redirect');

文档可以在这里找到 https://reactrouterdotcom.fly.dev/docs/en/v6/api#usenavigate


11

这是我唯一有效的方法:

window.history.pushState("", "", "/new-url");

或者替代:

window.history.replaceState("", "", "/new-url");

4

首先导入Link组件:

import { Link } from 'react-router-dom'

替代:

<Route path="landing" component={Landing} />

使用:

<Link to="landing" />

5
那么如果没有明确说明,React-Bootstrap如何知道显示“Landing”页面呢?没有“Route”组件,“/landing”或类似的链接是毫无意义的。 - Snackoverflow

1

以下是我在一些项目中使用的示例路由配置,它应该对你有所帮助:

import App from '../App';
import Home from '../components/pages/Home';
import Login from '../components/pages/Login';
import Register from '../components/pages/Register';

function shouldBeLoggedIn(nextState, replace) {
  // const status = getLoginStatus(); //From the State manager
  // if( status && !status.loggedin ){
  //   replace({
  //     pathname: '/login',
  //     state: { nextPathname: nextState.location.pathname }
  //   })
  // }
  console.log('Should be Logged in!')
}

function shouldNotBeLoggedIn(nextState, replace) {
  // const status = getLoginStatus();
  // if( status && status.loggedin ){
  //   replace({
  //     pathname: '/home',
  //     state: { nextPathname: nextState.location.pathname }
  //   })
  // }
  console.log('Should Not be Logged in!')
}

const rootRoute = {
  path: '/',
  component: App,
  indexRoute: {
    component: Login,
    onEnter: shouldNotBeLoggedIn
  },
  indexRedirect: {
    to: '/'
  },
  childRoutes: [ {
      path: 'home',
      component: Home,
      onEnter: shouldBeLoggedIn
    }, {
      path: 'login',
      component: Login,
      onEnter: shouldNotBeLoggedIn
    }, {
      path: 'register',
      component: Register,
      onEnter: shouldNotBeLoggedIn
    }
  ]
}

export default rootRoute;

在上述代码中,每个路由都有一个onEnter钩子来决定该路由是否应该进入。如果查看注释,您可以决定在挂钩方法中要执行什么操作。您可以在以下github存储库中浏览上述代码:http://github.com/pankajpatel/kickstart-react,文件位于https://github.com/pankajpatel/kickstart-react/blob/master/src/js/routes/routes.js。以下是来自react-router API文档的示例:
const userIsInATeam = (nextState, replace, callback) => {
  fetch(...)
    .then(response = response.json())
    .then(userTeams => {
      if (userTeams.length === 0) {
        replace(`/users/${nextState.params.userId}/teams/new`)
      }
      callback();
    })
    .catch(error => {
      // do some error handling here
      callback(error);
    })
}

<Route path="/users/:userId/teams" onEnter={userIsInATeam} />

1

React Router v4 - 重定向组件

react-router v4 的推荐方式是允许您的渲染方法捕获重定向。使用状态或属性来确定是否需要显示重定向组件。

参考资料:https://reacttraining.com/react-router/web/api/Redirect

  1. Import the Redirect from react-router.

    import { Redirect } from 'react-router';
    
  2. Define the Click event to change the state.

    handleOnClick = () => {
        // redirect
        this.setState({redirect: true});
    }
    
  3. Change Render method like,

    render() {
        if (this.state.redirect) {
        return <Redirect push to="/yourpath" />;
        }
    
        return ( <button onClick={this.handleOnClick} type="button">Button</button> );
    }
    
    • Example code :

      import { Redirect } from 'react-router'; //import Redirect 
      
      export default class ConfirmationDialog extends Component{
      
          constructor(props)
          {
              super(props);
              //init the state
              this.state = {
                  redirect : false
              }
          }
      
          handleOnClick = () => {
              //set the redirect property to true for allow redirect
              this.setState({redirect: true});
          }
      
          render() {
               //check if the redirec is allowed
               if (this.state.redirect) {
                    return <Redirect push to="/yourpath" />;
               }
               //if not put your code here
                return (
                        //your code
                        <button onClick={this.handleOnClick} 
                               type="button">Button</button>
                );
      
          }
      }
      

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