rutas route react proteger privateroute español auth reactjs redux react-router react-redux

reactjs - proteger - react router login redirect



Reaccionar enrutador de rutas privadas/redirigir no funciona (8)

He ajustado levemente el ejemplo de React Router para que las rutas privadas funcionen bien con Redux, pero no se representan los componentes al vincular o redirigir a otras ''páginas''. El ejemplo se puede encontrar aquí:

https://reacttraining.com/react-router/web/example/auth-workflow

Su componente PrivateRoute se ve así:

const PrivateRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={props => ( fakeAuth.isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: ''/login'', state: { from: props.location } }}/> ) )}/> )

Pero, debido a que lo he incorporado en una aplicación de Redux, tuve que ajustar un poco la PrivateRoute para poder acceder a la tienda de redux, así como a los accesorios de ruta:

const PrivateRouteComponent = (props) => ( <Route {...props.routeProps} render={() => ( props.logged_in ? ( <div>{props.children}</div> ) : ( <Redirect to={{ pathname: ''/login'', state: { from: props.location } }} /> ) )} /> ); const mapStateToProps = (state, ownProps) => { return { logged_in: state.auth.logged_in, location: ownProps.path, routeProps: { exact: ownProps.exact, path: ownProps.path } }; }; const PrivateRoute = connect(mapStateToProps, null)(PrivateRouteComponent); export default PrivateRoute

Siempre que no haya iniciado sesión y golpee un PrivateRoute, estoy correctamente redirigido a / login. Sin embargo, después de, por ejemplo, iniciar sesión y usar un <Redirect .../> , o hacer clic en cualquier <Link ...> a un PrivateRoute, el URI se actualiza, pero la vista no. Se queda en el mismo componente.

¿Qué estoy haciendo mal?

Solo para completar la imagen, en index.js la aplicación hay algunas cosas irrelevantes, y las rutas se configuran así:

ReactDOM.render( <Provider store={store}> <App> <Router> <div> <PrivateRoute exact path="/"><Home /></PrivateRoute> // ... other private routes <Route path="/login" component={Login} /> </div> </Router> </App> </Provider>, document.getElementById(''root'') );


Bueno, creo que la respuesta a esta pregunta debería ser realmente más detallada, así que aquí estoy, después de 4 horas de excavación.

Cuando envuelve su componente con connect (), React Redux implementa shouldComponentUpdate (sCU si busca respuestas sobre problemas de github) en él y realiza una comparación superficial en los accesorios (va a través de cada tecla en el objeto de accesorios y comprueba si los valores son idénticos a '' === ''). Lo que significa en la práctica es que su componente se considera puro . Ahora cambiará solo cuando cambien sus accesorios y solo entonces! Este es el mensaje clave aquí. Segundo mensaje clave, el enrutador React funciona con el contexto para pasar los objetos de ubicación, coincidencia e historial del enrutador al componente de enrutamiento. No usa puntales .

Ahora veamos en la práctica lo que sucede, porque aun sabiendo eso, lo encuentro bastante complicado:

  • Caso 1 :

Hay 3 claves para sus accesorios después de la conexión: ruta, componente y autenticación (dada por la conexión). Entonces, de hecho, su componente envuelto NO se volverá a generar en todos los cambios de ruta porque no le importa. Cuando la ruta cambia, sus accesorios no cambian y no se actualizarán.

  • Caso 3 :

Ahora hay 4 claves para tus accesorios después de conectar: ​​ruta, componente, auth y anyprop. El truco aquí es que anyprop es un objeto que se crea cada vez que se llama al componente. Entonces, cuando se llama a su componente, se hace esta comparación: {a: 1} === {a: 1}, que (puede probar) le da falso, por lo que su componente ahora se actualiza cada vez. Sin embargo, tenga en cuenta que a su componente todavía no le importa la ruta, sus hijos sí lo hacen.

  • Caso 2 :

Ese es el misterio aquí, porque supongo que llamas a esta línea en tu archivo de la aplicación, y no debería haber ninguna referencia a "auth" allí, y deberías tener un error (al menos eso es lo que estoy diciendo). Mi conjetura es que "auth" en su archivo de aplicación hace referencia a un objeto definido allí.

Ahora, ¿qué debemos hacer?

Veo dos opciones aquí:

  1. Dígale a React Redux que su componente no es puro, esto eliminará la inyección sCU y su componente ahora se actualizará correctamente.

    connect (mapStateToProps, null, null, {pure: false}) (PrivateRoute)

  2. Use WithRouter (), que resultará en inyectar la ubicación, el partido y el objeto histórico a su componente como accesorios. Ahora, no conozco las partes internas, pero sospecho que el enrutador React no muta esos objetos, así que cada vez que cambia la ruta, cambian sus propiedades (sCU devuelve true) y su componente se actualiza correctamente. El efecto secundario de esto es que su árbol React ahora está contaminado con una gran cantidad de WithRouter y Route stuff ...

Referencia al problema de github: Cómo lidiar con el bloqueo de actualización

Puede ver aquí que withRouter está pensado como una solución rápida pero no como una solución recomendada. usar pure: false no se menciona, así que no sé qué tan buena podría ser esta solución.

Encontré una tercera solución , aunque no me queda claro si es realmente una mejor solución que con Router, utilizando el componente de orden superior. Usted conecta su Componente de orden superior a la tienda Redux, y ahora a su ruta no le importa lo que haga, el HOC se ocupa de ello.

// before export default connect(mapStateToProps)(Something) // after import { withRouter } from ''react-router-dom'' export default withRouter(connect(mapStateToProps)(Something))

en tu app.js

import Notlogged from "./Notlogged"; function Isloggedhoc({ wrap: Component, islogged, ...props }) { return islogged ? <Component {...props} /> : <Notlogged {...props} />; } const mapState = (state, ownprops) => ({ islogged: state.logged, ...ownprops }); export default connect(mapState)(Isloggedhoc);

Incluso podrías hacer una función al curry para acortarlo un poco:

<Route path="/PrivateRoute" render={props => <Isloadedhoc wrap={Mycomponent} />} />

Usándolo de esa manera:

function isLogged(component) { return function(props) { return <Isloadedhoc wrap={component} {...props} />; }; }


De acuerdo con la documentación de react-router , puede simplemente ajustar su función de connect con withRouter :

<Route path="/PrivateRoute" render={isLogged(Mycomponent)} />

Esto funcionó para mí y mis opiniones comenzaron a actualizarse junto con las rutas en este caso.



Necesitas envolver tu Route con la etiqueta <Switch>

ReactDOM.render( <Provider store={store}> <App> <Router> <div> <Switch> <PrivateRoute exact path="/"><Home /></PrivateRoute> // ... other private routes <Route path="/login" component={Login} /> </Switch> </div> </Router> </App> </Provider>, document.getElementById(''root''));


Solo tuve el mismo problema, lo resolví haciendo que mi aplicación reduxte el contenedor y pasé isAuthenticated como prop para PrivateRoute

Aquí está, espero que ayude.

const App = (props) => { return ( <Provider store={store}> <Router> <div> <PrivateRoute path="/secured" component={Secured} isAuthenticated={props.isAuthenticated} /> </div> </Router> </Provider> ); }; const mapStateToProps = state => ({ isAuthenticated: state.isAuthenticated }); export default connect(mapStateToProps)(App);

Entonces en mi PrivateRoute

const PrivateRoute = ({ component: Component, isAuthenticated, ...rest}) => ( <Route {...rest} render={props => ( isAuthenticated ? ( <Component {...props} /> ) : (<Redirect to={{ pathname: ''/login'', state: { from: props.location} }} />) )} /> ); export default PrivateRoute;


También he luchado con este problema, y ​​aquí está mi solución.

En lugar de pasar isAuthenticated a cada componente <PrivateRoute>, solo necesita obtener isAuthenticated del estado en <PrivateRoute>.

import React from ''react''; import {Route, Redirect, withRouter} from ''react-router-dom''; import {connect} from ''react-redux''; // isAuthenticated is passed as prop here const PrivateRoute = ({component: Component, isAuthenticated , ...rest}) => { return <Route {...rest} render={ props => { return isAuthenticated ? ( <Component {...props} /> ) : ( <Redirect to={{ pathname: "/login", state: {from: props.location} }} /> ) } } /> }; const mapStateToProps = state => ( { // isAuthenticated value is get from here isAuthenticated : state.auth.isAuthenticated } ); export default withRouter(connect( mapStateToProps, null, null, {pure: false} )(PrivateRoute));


Tengo el problema similar como @Rein. En mi caso, PrivateRoute parece casi igual a la versión original, pero solo se conectó a Redux y lo usó en lugar de fakeAuth en el ejemplo original.

const PrivateRoute = ({ component: Component, auth, ...rest }) => ( <Route {...rest} render={props => auth.isAuthenticated ? <Component {...props} /> : <Redirect to={{ pathname: "/login" }} />} /> ); PrivateRoute.propTypes = { auth: PropTypes.object.isRequired, component: PropTypes.func.isRequired } const mapStateToProps = (state, ownProps) => { return { auth: state.auth } }; export default connect(mapStateToProps)(PrivateRoute);

Uso y resultado: -

  1. NO trabajando pero esperando trabajar
    • <PrivateRoute path="/member" component={MemberPage} />
  2. trabajando pero NO se desea utilizar como este
    • <PrivateRoute path="/member" component={MemberPage} auth={auth} />
  3. trabajando. SOLO para trabajar pero NO desea utilizar en absoluto. Un entendimiento a partir de este punto es que, si conecta PrivateRoute original a Redux, necesita pasar algunos apoyos adicionales (cualquier prop) para hacer que PrivateRoute funcione, de lo contrario no funcionará. Alguien, por favor, dale una pista sobre este comportamiento . Esta es mi principal preocupación. Como una nueva pregunta en
    • <PrivateRoute path="/member" component={MemberPage} anyprop={{a:1}} />

mapStateToProps funcionara usando el parámetro rest para acceder a los datos de mapStateToProps :

const PrivateRoute = ({component: Component, ...rest}) => { const {isAuthenticated} = rest; return ( <Route {...rest} render={props => ( isAuthenticated ? ( <Component {...props}/> ) : ( <Redirect to={{ pathname: ''/login'', state: {from: props.location} }}/> ) )} /> ); }; PrivateRoute.propTypes = { isAuthenticated: PropTypes.bool.isRequired, }; function mapStateToProps(state) { return { isAuthenticated: state.user.isAuthenticated, }; } export default connect(mapStateToProps)(PrivateRoute);