Stuart Fong
Stuart Fong

Reputation: 633

react router v4 redirecting to another page outside of component

I have a basic texting app I want to make and am following a tutorial on react and meteor but the only problem is that the tutorial is using react-router v3 and I want to get used to react-router v4. How would I make the equivalent of doing something like:

browserHistory.replace("/chat");

I also am doing it outside of a component so I cannot do:

this.props.history.push("/chat");

I am trying to run a function every time someone is entering a page, which checks if the user is authenticated or not and what page they are on. Here is my code so far:

Main.js

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

import {Texts} from "./../imports/api/Text";
import App from "./../imports/ui/App";
import Name from "./../imports/ui/Name";
import NotFound from "./../imports/ui/NotFound";
import Signup from "./../imports/ui/Signup";
import Login from "./../imports/ui/Login";

Meteor.startup(() => {
    Tracker.autorun(() => {
        let texts = Texts.find().fetch();
        let signedIn = !!Meteor.userId();
        let onPrivatePage = ["/chat"];
        let onPublicPage = ["/signup", "/login"];
        const isUserAuthenticated = withRouter(({history}) => {
            if(signedIn && onPublicPage){
                console.log("Signed In")
            }
            if(!signedIn && onPrivatePage){
                console.log("Signed Out")
            }
        });
        const routes = (
            <BrowserRouter>
                <Switch>
                    <App path="/chat" texts={texts} render={isUserAuthenticated()}/>
                    <Signup path="/signup" render={isUserAuthenticated()}/>
                    <Login path="/login" render={isUserAuthenticated()}/>
                    <Route component={NotFound}/>
                </Switch>
            </BrowserRouter>
        );
        ReactDOM.render(routes, document.getElementById("app"));
    });
});

Signup.js

import React from "react"
import {withRouter} from "react-router-dom";
import {Accounts} from "meteor/accounts-base"
import {Link} from "react-router-dom";

class Signup extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            error: ""
        }
    }
    SignupUser(e){
        e.preventDefault();
        let username = this.refs.username.value;
        let password = this.refs.password.value;

        User = {
            username,
            password
        };

        Accounts.createUser(User, (err) => {
            if(err){
                this.setState({
                    error:err.reason
                })
            }else{
                console.log("success")
            }
        });
    }
    render(){
        return(
            <div>
                <form onSubmit={this.SignupUser.bind(this)}>
                    <h1>Register Here</h1>
                    {this.state.error}
                    <br />
                    <input type="username" ref="username" />
                    <input type="password" ref="password" />
                    <button>Signup</button>
                    <br />
                    <Link to="/login">I already have an account.</Link>
                </form>
            </div>

        )
    }
}
export default withRouter(Signup);

Login.js

import React from "react";
import {withRouter} from "react-router-dom";
import {Meteor} from "meteor/meteor";
import {Link} from "react-router-dom";

class Login extends React.Component{
    constructor(props){
        super(props)
        this.state = {
            error:""
        }
    }
    loginUser(e){
        e.preventDefault()
        let username = this.refs.username.value.trim();
        let password = this.refs.password.value.trim();

        Meteor.loginWithPassword({username}, password, (err)=>{
            if(err){
                this.setState({
                    error: err.reason
                })
            }else{
                console.log("Logged in")
            }
        });
    }
    render(){
        return(
            <div>
                <form onSubmit={this.loginUser.bind(this)}>
                    <h1>Login</h1>
                    {this.state.error}
                    <br />
                    <input ref="username" type="text" placeholder="Username" />
                    <input ref="password" type="password" placeholder="Password" />
                    <button>Login</button>
                    <br />
                    <Link to="/signup">Need an account?</Link>
                </form>

            </div>
        )
    }
}

export default withRouter(Login);

Upvotes: 2

Views: 4592

Answers (2)

Mikkel
Mikkel

Reputation: 7777

There is another way to do this that is more React Router v4 friendly, and is actually a lot less fuss, and involves using the Redirect component

Import the component like this:

import { Link, Redirect } from 'react-router-dom';

In your render method do something like this:

if (!Meteor.userId())
  return <Redirect to={"/login"} />

Or if you want to push it onto the history add the push property

if (!Meteor.userId())
  return <Redirect to={"/login"} push />

Upvotes: 0

Brunno Vodola Martins
Brunno Vodola Martins

Reputation: 1692

Change your isUserAuthenticated code to the following:

const isUserAuthenticated = withRouter(({history}) => {
    if(signedIn && onPublicPage){
        console.log("Signed In")
    }
    if(!signedIn && onPrivatePage){
        console.log("Signed Out")
    }
});

So you will be able to do the history.push('/some-route/') when needed. Just don't forget to add withRouter in your import from react-router-dom, like this:

import { BrowserRouter, Route, Switch, Redirect, withRouter } from 'react-router-dom'

As for the auth flow, checkout this auth example from React Router 4 docs. It will definitely help you!

Upvotes: 3

Related Questions