Как маршрутизировать без перезагрузки всей страницы?

#reactjs #react-router

#reactjs #react-маршрутизатор

Вопрос:

Я использую react-route, и у меня возникли некоторые проблемы с маршрутизацией.

Перезагружается вся страница, в результате чего все данные, которые я уже извлек и сохранил в редукторе, загружаются каждый раз.

Вот мой файл маршрута :

 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>
    },
});
  

Перед маршрутизацией я уже сохраняю данные, вызывая action в моем 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"
    }
}));  
  

Окно.местоположение делает свое дело, но оно перезагружает все, что очень неэффективно.
В ручном маршруте я использую <Link> эти маршруты без перезагрузки, однако для автоматического я не уверен, как это сделать.

Любое предложение будет высоко оценено.

Ответ №1:

для самой последней версии ( v2.0.0-rc5 ) рекомендуемый метод навигации — прямое нажатие на синглтон истории.

ДЕМОНСТРАЦИЯ

Соответствующий код

 import { browserHistory } from './react-router'
browserHistory.push('/some/path')
  

При использовании более нового API-интерфейса react-router вам необходимо использовать history from this.props when внутри компонентов, чтобы:

 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

Комментарии:

1. Большое спасибо, это помогло мне. Просто импортируйте var browserHistory = require('react-router').browserHistory и вызывайте browserHistory.push('/form') .

2. Я сделал это, и вся страница все еще обновляется

3. Ссылка на демонстрационный пример недоступна (404). Ссылка на дополнительную информацию также недоступна. Можете ли вы обновить этот ответ?

Ответ №2:

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

Ответ №3:

Это единственное, что сработало для меня:

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

ИЛИ заменить:

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

Ответ №4:

Сначала импортируйте компонент ссылки :

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

вместо :

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

используйте :

 <Link to="landing" />
  

Комментарии:

1. Тогда как React-Bootstrap должен знать, показывать Landing ли страницу, если она даже не указана? Ссылка на «/ landing» или что-либо подобное не имеет смысла без Route компонента..

Ответ №5:

Ниже приведен пример конфигурации маршрутов, который я использовал в некоторых своих проектах, и он должен быть вам полезен:

 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 amp;amp; !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 amp;amp; 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

Ниже приведен пример из документации API для react-router:

 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} />
  

Ответ №6:

React Router v4 — компонент перенаправления

Рекомендуемый способ react-router v4 — разрешить вашему методу рендеринга перехватывать перенаправление. Используйте state или props, чтобы определить, нужно ли показывать компонент перенаправления.

Ссылка : https://reacttraining.com/react-router/web/api/Redirect

  1. Импортируйте Redirect из react-router .

     import { Redirect } from 'react-router';
      
  2. Определите событие щелчка, чтобы изменить состояние.

     handleOnClick = () => {
        // redirect
        this.setState({redirect: true});
    }
      
  3. Измените метод визуализации, например,

     render() {
        if (this.state.redirect) {
        return <Redirect push to="/yourpath" />;
        }
    
        return ( <button onClick={this.handleOnClick} type="button">Button</button> );
    }
      
    • Пример кода :

       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>
                );
      
          }
      }