Estoy desarrollando una aplicación en la que compruebo si el usuario no ha loggedIn . Tengo que mostrar el formulario de inicio de sesión, de lo contrario dispatch una action que cambiaría la ruta y cargaría otro componente. Aquí está mi código:
render() { if (isLoggedIn) { // dispatch an action to change the route } // return login component <Login /> } ¿Cómo puedo lograr esto ya que no puedo cambiar los estados dentro de la función de render ?
Teniendo en cuenta que está utilizando react-router v4
Use su componente con withRouter y use history.push from props para cambiar la ruta. Debe usar withRouter solo cuando su componente no recibe los accesorios del Router , esto puede suceder en los casos en que su componente es un elemento secundario anidado de un componente representado por el enrutador y no le ha pasado los accesorios del enrutador o cuando el componente no está vinculado al enrutador en absoluto y se representa como un componente separado de las rutas.
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);Nota IMPORTANTE
Si está utilizando
withRouterpara evitar queshouldComponentUpdatebloquee las actualizaciones, es importante quewithRouterenvuelva el componente que implementashouldComponentUpdate. Por ejemplo, al usar Redux:// Esto se
shouldComponentUpdatewithRouter(connect(...)(MyComponent))// Esto no lo hace
connect(...)(withRouter(MyComponent))
o podrías usar Redirigir
import {withRouter} from 'react-router'; class App extends React.Component { ... render() { if(isLoggedIn) { return <Redirect to="/home"/> } // return login component return <Login /> } } Con react-router v2 or react-router v3 , puede utilizar el context para cambiar dinámicamente la ruta como
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;o usar
import { browserHistory } from 'react-router'; browserHistory.push('/some/path');En reaccionar-router versión 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;Otra alternativa es manejar esto usando acciones asincrónicas de estilo Thunk (que son seguras/pueden tener efectos secundarios).
Si usa Thunk, puede inyectar el mismo objeto de history tanto en su componente <Router> como en las acciones de Thunk usando thunk.withExtraArgument , así:
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) Luego, en sus creadores de acciones, tendrá una instancia de history que es segura de usar con ReactRouter, por lo que puede activar un evento Redux normal si no ha iniciado sesión:
// meanwhile... in action-creators.js export const notLoggedIn = () => { return (dispatch, getState, {history}) => { history.push(`/login`) } }Otra ventaja de esto es que la URL ahora es más fácil de manejar, por lo que podemos poner información de redireccionamiento en la cadena de consulta, etc.
Puede intentar seguir haciendo esta verificación en sus métodos Render, pero si causa problemas, podría considerar hacerlo en componentDidMount , o en otra parte del ciclo de vida (¡aunque también entiendo el deseo de seguir con Stateless Functional Compeonents!)
Todavía puede usar Redux y mapDispatchToProps para inyectar el creador de la acción en su componente, por lo que su componente aún está ligeramente conectado a Redux.