【问题标题】:React Router v4 Redirect fails to redirectReact Router v4 Redirect 无法重定向
【发布时间】:2017-07-18 21:17:47
【问题描述】:

onEnter 替换为render 我更改了代码以匹配路由器v4 规范。关键是防止登录时显示/signup 页面。我的代码中遗漏了什么?

import React from 'react';
import ReactDOM from 'react-dom';
import {Meteor} from 'meteor/meteor';
import {BrowserRouter, Route, Redirect, Switch} from 'react-router-dom';
import browserHistory from 'history';
import {Tracker} from 'meteor/tracker';

import Signup from '../imports/ui/Signup';
import MyLink from '../imports/ui/MyLink';
import NotFound from '../imports/ui/NotFound';
import Login from '../imports/ui/Login';

const history = browserHistory.createBrowserHistory();

const unathenticatedPages = ['/', '/signup'];
const athenticatedPages = ['/mylink'];
const onEnterPublicPage = () => {
  if (Meteor.userId()) {
    return <Redirect to="/mylink/" />;
  }
};

const routes = (
  <BrowserRouter history={history}>
    <Switch>
      <Route exact path="/" component={Login} render={() => onEnterPublicPage} />
      <Route path="/signup" component={Signup} render={() => onEnterPublicPage} />
      <Route path="/login" component={Login} />
      <Route path="/mylink" component={MyLink} />
      <Route path="*" component={NotFound} />
    </Switch>
  </BrowserRouter>
);

Tracker.autorun(() => {
  const isAuthenticated = !!Meteor.userId();    
  const pathname = history.location.pathname;

  const isUnathenticatedPage = unathenticatedPages.includes(pathname);
  const isAthenticatedPage = athenticatedPages.includes(pathname);

  if (isAuthenticated && isUnathenticatedPage) {
    history.push('/mylink');
  } else if (!isAuthenticated && isAthenticatedPage) {
    history.push('/');
  }
});

Meteor.startup(() => {
  ReactDOM.render(routes, document.getElementById('app'));
});

【问题讨论】:

    标签: reactjs meteor react-router-v4


    【解决方案1】:

    使用 React Router 4,您不再像那样使用 Browserhistory。相反,它包含在 BrowserRouter 中,就像您看到的 in the documentation

    另外,我不确定这是否能解决正在发生的事情,但我制作了一个 App 组件并将我的路由放在那里。然后,在 v4 中,历史记录在 props 中出现。然后你可以运行你的逻辑并执行props.history.push(url)

    编辑:这是我用来让它工作的代码:

    import React from 'react';
    import Header from './Header';
    import BinsList from './bins/BinsList';
    import BinsMain from './bins/BinsMain';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    
    const App = (props) => {
      return (
        <Router>
          <div>
            <Header />
            <Switch>
              <Route exact path="/" component={BinsList}></Route>
              <Route path="/bins/:binId" component={BinsMain}></Route>
            </Switch>
          </div>
        </Router>
      );
    }
    
    export default App;
    

    我的标题是这样渲染的:

    import React, { Component } from 'react';
    import Accounts from './Accounts';
    import { Link, Redirect, withRouter } from 'react-router-dom'
    
    
    class Header extends Component {
      onBinClick(e){
        e.preventDefault();
        Meteor.call('bins.insert', (err, bin) => {
          const url = `/bins/${bin}`;
          this.props.history.push(url);
        });
      }
    
      render() {
        return (
          <nav className="nav navbar-default">
            <div className="navbar-header">
              <Link to="/" className="navbar-brand">MarkBin</Link>
            </div>
            <ul className="nav navbar-nav">
              <li>
                <Accounts />
              </li>
              <li>
                <a href="#" onClick={this.onBinClick.bind(this)}>Create Bin</a>
              </li>
            </ul>
          </nav>
        );
      }
    }
    
    export default withRouter(Header);
    

    【讨论】:

    • 谢谢。你能修复一下文档链接吗?它导致文档的开始
    • 这实际上是故意的,因为在开始的安装部分,它显示了如何使用 BrowserRouter。但如果有帮助,这里是 BrowserRouter 的链接:reacttraining.com/react-router/web/api/BrowserRouter
    • 我从&lt;BrowserRouter ...&gt;&lt;/BrowserRouter&gt; 中删除了history={history}history 对象在 MyLink 组件中被访问,例如 this.props.history.push('/login');。该应用程序似乎继续正常工作。这就是您所说的关于使用 BrowserRouter 的内容吗?
    • 是的!这就是我所指的。现在是否按预期工作?
    • 按照您的方式构建路由变量让人想起 React Router v3。它仍然可以工作,但是它的创建者之一 Tyler McGinnis 教它的方式是将您的路线放在主要组件中(例如,App),然后历史记录在该组件的道具中。如果这仍然不起作用,您可以随时导出该组件withRouting。我已经添加了像上面这样工作的代码。
    【解决方案2】:

    现在几乎可以使用这些更改:

    import React from 'react';
    import ReactDOM from 'react-dom';
    import {Meteor} from 'meteor/meteor';
    import {BrowserRouter, Route, Redirect, Switch} from 'react-router-dom';
    import browserHistory from 'history';
    import {Tracker} from 'meteor/tracker';
    
    import Signup from '../imports/ui/Signup';
    import MyLink from '../imports/ui/MyLink';
    import NotFound from '../imports/ui/NotFound';
    import Login from '../imports/ui/Login';
    
    const history = browserHistory.createBrowserHistory();
    
    const unathenticatedPages = ['/', '/signup'];
    const athenticatedPages = ['/mylink'];
    const isLoggedIn = () => {
      return Meteor.userId() !== null;
    };
    
    const routes = (
      <BrowserRouter>
        <Switch >
          <Route exact path="/" render={() => (isLoggedIn() ? <Redirect to="/mylink"/> : <Login/>)} />
          <Route path="/signup" render={() => (isLoggedIn() ? <Redirect to="/mylink"/> : <Signup/>)} />
          <Route path="/login" render={() => (isLoggedIn() ? <Redirect to="/mylink"/> : <Login/>)} />
          <Route path="/mylink" render={() => (!isLoggedIn() ? <Login/> : <MyLink history={history}/>)} />
          <Route path="*" component={NotFound} />
        </Switch>
      </BrowserRouter>
    );
    
    Tracker.autorun(() => {
      const isAuthenticated = !!Meteor.userId();
      console.log("isAuthenticated: ", isAuthenticated);
    
      const pathname = history.location.pathname;
      console.log("pathname: ", pathname);
    
      const isUnathenticatedPage = unathenticatedPages.includes(pathname);
      const isAthenticatedPage = athenticatedPages.includes(pathname);
    
      if (isLoggedIn() && isUnathenticatedPage) {
        history.replace('/mylink');
      } else if (!isLoggedIn() && isAthenticatedPage) {
        history.replace('/');
      }
    });
    
    Meteor.startup(() => {
      ReactDOM.render(routes, document.getElementById('app'));
    });
    

    MyLink.js 组件:

    import React from 'react';
    import {Accounts} from 'meteor/accounts-base';
    import {withRouter} from 'react-router-dom';
    
    class MyLink extends React.Component {    
      navigate(evt) {
        evt.preventDefault();
        this.props.history.push('/notfound');
      }
    
      onLogout() {
        Accounts.logout();
      }
    
      render() {
        return (
          <div>
            <p>MyLink</p>
            <button onClick={this.navigate.bind(this)}>Go to Not Found page</button>
            <br/>
            <button onClick={this.onLogout.bind(this)}>Log out</button>
          </div>
        );
      }
    }
    
    export default withRouter(MyLink);
    

    【讨论】:

    • 不要使用带有单击事件的按钮尝试将 url 推送到历史记录,只需使用 React Router v4 Link 标签:reacttraining.com/react-router/web/api/Link
    • 谢谢。这是我在这里遵循的教程。我很好奇是否有办法在渲染组件位于render() 中时向它们添加属性。好像没有。
    猜你喜欢
    • 1970-01-01
    • 2017-11-15
    • 2019-10-02
    • 2020-12-22
    • 2017-11-02
    • 2017-11-14
    • 2017-02-20
    • 1970-01-01
    • 2017-08-10
    相关资源
    最近更新 更多