route react doom javascript reactjs react-router redux

javascript - react - redux router dom



Acceder a la Tienda Redux desde las rutas configuradas a través del Router React (3)

Me gustaría utilizar el manejador onEnter de onEnter -router para solicitar a los usuarios que se autentiquen al ingresar a una ruta restringida.

Hasta ahora, mi archivo routes.js ve así:

import React from ''react''; import { Route, IndexRoute } from ''react-router''; export default ( <Route path="/" component={App}> <IndexRoute component={Landing} /> <Route path="learn" component={Learn} /> <Route path="about" component={About} /> <Route path="downloads" component={Downloads} onEnter={requireAuth} /> </Route> )

Idealmente, me gustaría que mi función requireAuth sea ​​una acción de reducción que tenga acceso a la tienda y al estado actual, que funcione así: store.dispatch(requireAuth()) .

Lamentablemente, no tengo acceso a la tienda en este archivo. No creo que pueda usar realmente use connect en este caso para acceder a las acciones relevantes que deseo. Tampoco puedo import store del archivo donde se crea la tienda, ya que no está definida cuando la aplicación se carga por primera vez.


La forma más fácil de lograr esto es pasar su tienda a una función que devuelve sus rutas (en lugar de devolver sus rutas directamente). De esta forma, puede acceder a la tienda en onEnter y otros métodos de reacción de enrutadores.

Entonces para tus rutas:

import React from ''react''; import { Route, IndexRoute } from ''react-router''; export const getRoutes = (store) => ( const authRequired = (nextState, replaceState) => { // Now you can access the store object here. const state = store.getState(); if (!state.user.isAuthenticated) { // Not authenticated, redirect to login. replaceState({ nextPathname: nextState.location.pathname }, ''/login''); } }; return ( <Route path="/" component={App}> <IndexRoute component={Landing} /> <Route path="learn" component={Learn} /> <Route path="about" component={About} /> <Route path="downloads" component={Downloads} onEnter={authRequired} /> </Route> ); )

Luego actualice su componente principal para llamar a la función getRoutes , pasando en la tienda:

<Provider store={ store }> <Router history={ history }> { getRoutes(store) } </Router> </Provider>

En cuanto a enviar una acción desde requireAuth , podría escribir su función de esta manera:

const authRequired = (nextState, replaceState, callback) => { store.dispatch(requireAuth()) // Assume this action returns a promise .then(() => { const state = store.getState(); if (!state.user.isAuthenticated) { // Not authenticated, redirect to login. replaceState({ nextPathname: nextState.location.pathname }, ''/login''); } // All ok callback(); }); };

Espero que esto ayude.


Muchos han cambiado con el tiempo. onEnter ya no existe en react-router-4

El siguiente es de mi proyecto real para su referencia

export const getRoutes = (store) => { const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( checkIfAuthed(store) ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: ''/login'' }}/> ) )}/> ) return ( <Router> <div> <PrivateRoute exact path="/" component={Home}/> <Route path="/login" component={Login} /> </div> </Router> ) }


Si quieres, puedes escribir route.js así:

var requireAuth = (store, nextState, replace) => { console.log("store: ", store); //now you have access to the store in the onEnter hook! } export default (store) => { return ( <Route path="/" component={App}> <IndexRoute component={Landing} /> <Route path="learn" component={Learn} /> <Route path="about" component={About} /> <Route path="downloads" component={Downloads} onEnter={requireAuth.bind(this, store)} /> </Route> ); );

He configurado un ejemplo con el que puedes jugar en este codepen .

No estoy seguro de si activar una acción para manejar la autenticación es una buena idea. Personalmente prefiero manejar auth de una manera diferente :

En lugar de usar un gancho onEnter , utilizo una función de envoltura. Quiero que la sección de administración de mi blog requireAuthentication protegida, por lo tanto, envolví el componente AdminContainer en las rutas con una función, requireAuthentication , ver a continuación.

export default (store, history) => { return ( <Router history={history}> <Route path="/" component={App}> { /* Home (main) route */ } <IndexRoute component={HomeContainer}/> <Route path="post/:slug" component={PostPage}/> { /* <Route path="*" component={NotFound} status={404} /> */ } </Route> <Route path="/admin" component={requireAuthentication(AdminContainer)}> <IndexRoute component={PostList}/> <Route path=":slug/edit" component={PostEditor}/> <Route path="add" component={PostEditor}/> </Route> <Route path="/login" component={Login}/> </Router> ); };

requireAuthentication es una función que

  • si el usuario está autenticado, procesa el componente envuelto,
  • de lo contrario redirige a Login

Puedes verlo a continuación:

export default function requireAuthentication(Component) { class AuthenticatedComponent extends React.Component { componentWillMount () { this.checkAuth(); } componentWillReceiveProps (nextProps) { this.checkAuth(); } checkAuth () { if (!this.props.isAuthenticated) { let redirectAfterLogin = this.props.location.pathname; this.context.router.replace({pathname: ''/login'', state: {redirectAfterLogin: redirectAfterLogin}}); } } render () { return ( <div> {this.props.isAuthenticated === true ? <Component {...this.props}/> : null } </div> ) } } const mapStateToProps = (state) => ({ isAuthenticated: state.blog.get(''isAuthenticated'') }); AuthenticatedComponent.contextTypes = { router: React.PropTypes.object.isRequired }; return connect(mapStateToProps)(AuthenticatedComponent); }

Además, requireAuthentication protegerá todas las rutas en /admin . Y puedes reutilizarlo donde quieras.