redux 使用react-router以编程方式导航

z9gpfhce  于 2022-11-12  发布在  React
关注(0)|答案(9)|浏览(119)

我正在开发一个应用程序,在其中我检查用户是否不是loggedIn。我必须显示登录表单,否则dispatchaction将改变路由并加载其他组件。下面是我的代码:

render() {
    if (isLoggedIn) {
        // dispatch an action to change the route
    }
    // return login component
    <Login />
}

我如何才能做到这一点,因为我不能改变render函数内部的状态。

u5i3ibmn

u5i3ibmn1#

考虑到您使用的是react-router v4
将组件与withRouter一起使用,并使用来自props的history.push来更改路由。只有当组件不接收Router props时,才需要使用withRouter,当您的组件是路由器呈现的组件的嵌套子组件,并且您尚未“t将路由器属性传递给它,或者当组件根本没有链接到路由器,并且呈现为与路由器分离的组件时。

import {withRouter} from 'react-router';

class App extends React.Component {
     ...
     componenDidMount() {
        // get isLoggedIn from localStorage or API call
        if (isLoggedIn) {
             // dispatch an action to change the route
             this.props.history.push('/home');
        }
     }
     render() {
         // return login component
         return <Login />
    }
}

export default withRouter(App);

重要说明

如果您使用withRouter来防止shouldComponentUpdate封锁更新,则withRouter必须 Package 实作shouldComponentUpdate的元件。例如,使用Redux时:
//这会得到shouldComponentUpdate左右的值

withRouter(connect(...)(MyComponent))

//这不

connect(...)(withRouter(MyComponent))

或者您可以使用重定向

import {withRouter} from 'react-router';

class App extends React.Component {
     ...
     render() {
         if(isLoggedIn) {
              return <Redirect to="/home"/>
         }
         // return login component
         return <Login />
    }
}

通过react-router v2 or react-router v3,您可以使用context动态更改路由,如下所示

class App extends React.Component {
     ...
     render() {
         if (isLoggedIn) {
             // dispatch an action to change the route
             this.context.router.push('/home');
         }
         // return login component
         return <Login />
    }
}

App.contextTypes = {
    router: React.PropTypes.object.isRequired
}
export default App;

或使用

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

j2datikz2#

在React路由器版本4中:

import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'

const Example = () => (

  if (isLoggedIn) {
    <OtherComponent />

  } else {

    <Router>
      <Redirect push to="/login" />
      <Route path="/login" component={Login}/>
    </Router>

  }
)

const Login = () => (
    <h1>Form Components</h1>
    ...
)

export default Example;
tvz2xvvm

tvz2xvvm3#

另一种选择是使用Thunk风格的异步操作(这是安全的/允许有副作用)来处理这个问题。
如果您使用Thunk,则可以使用thunk.withExtraArgument将相同的history对象注入到<Router>组件和Thunk操作中,如下所示:

import React from 'react'
import { BrowserRouter as Router, Route, Redirect} from 'react-router-dom'
import { createBrowserHistory } from "history"
import { applyMiddleware, createStore } from "redux"
import thunk from "redux-thunk"

const history = createBrowserHistory()

const middlewares = applyMiddleware(thunk.withExtraArgument({history}))
const store = createStore(appReducer, middlewares)

render(
  <Provider store={store}
    <Router history={history}>
      <Route path="*" component={CatchAll} />
    </Router
  </Provider>,
appDiv)

然后在动作创建器中,您将拥有一个可以安全地与ReactRouter一起使用的history示例,因此如果您没有登录,您可以只触发一个常规Redux事件:

// meanwhile... in action-creators.js
export const notLoggedIn = () => {
  return (dispatch, getState, {history}) => {
    history.push(`/login`)
  }
}

这样做的另一个好处是URL更容易处理,所以我们可以把重定向信息放在查询字符串上,等等。
您还可以尝试在Render方法中执行此检查,但如果它导致问题,您可能会考虑在componentDidMount中或生命周期的其他地方执行此检查(尽管我也理解坚持使用无状态功能能力的愿望!)
您仍然可以使用Redux和mapDispatchToProps将操作创建器注入到组件中,因此您的组件仍然只是松散地连接到Redux。

x759pob2

x759pob24#

这是我的代号
如果用户已登录,则允许PrivateRoute输入path,并将令牌保存到localStorge

function PrivateRoute({ component: Component, ...rest }) {
     return (
        <Route
          {...rest}
          render={props => (localStorage.token) ? <Component {...props} /> : (
            <Redirect
              to={{
                pathname: '/signin',
                state: { from: props.location },
              }}
            />
          )
          }
        />
      );
    }

在此处定义应用程序中的所有路径

export default (
  <main>
    <Switch>
      <Route exact path="/signin" component={SignIn} />
      <Route exact path="/signup" component={SignUp} />
      <PrivateRoute path="/" component={Home} />
    </Switch>
  </main>
);
e5nszbig

e5nszbig5#

那些在react-router v4上实施此功能时遇到问题的人。下面是一个通过react应用程序编程导航的工作解决方案。
history.js

import createHistory from 'history/createBrowserHistory'

export default createHistory()

App.js或Route. jsx。将历史记录作为属性传递给路由器。

import { Router, Route } from 'react-router-dom'
import history from './history'
...
<Router history={history}>
 <Route path="/test" component={Test}/>
</Router>

您可以使用push()进行导航。

import history from './history' 

...

render() {
     if (isLoggedIn) {
         history.push('/test') // this should change the url and re-render Test component
     }
     // return login component
     <Login />
}

这一切都要归功于这条评论:https://github.com/ReactTraining/react-router/issues/3498#issuecomment-301057248

hpcdzsge

hpcdzsge6#

render(){ 

    return (
        <div>  
            { this.props.redirect ? <Redirect to="/" /> :'' } 
            <div>
                add here component codes
            </div>
        </div>
    );
}
2jcobegt

2jcobegt7#

我建议您使用connected-react-routerhttps://github.com/supasate/connected-react-router,它可以帮助您执行导航,如果您愿意,甚至可以从reducer/actions执行导航。它有很好的文档记录,易于配置

vdgimpew

vdgimpew8#

我能够在无状态功能组件中使用history,使用withRouter的方式如下(需要忽略typescript警告):

import { withRouter } from 'react-router-dom';

...

type Props = { myProp: boolean };

// @ts-ignore
export const MyComponent: FC<Props> = withRouter(({ myProp, history }) => {

...

})
368yc8dk

368yc8dk9#

import { useNavigate } from "react-router-dom"; //with v6

export default function Component() {
  const navigate = useNavigate();
  navigate.push('/path');
}

我遇到了这个问题,并且用react-router-dom版本6中的新useNavigate钩子解决了这个问题

相关问题