I'm using react-router-dom v5.2.
Upon login, I want my page to redirect to /home
from /
. The login form is at /
.
When I try to perform authentication without any async function (ie. comparing username and password to hardcoded values in react), everything works perfectly.
But when I do perform authentication using express and mongo, the redirection upon login stops working. If I login again, then the redirection happens. Protected routes still work (redirect to login page if the user is not logged in).
Here's a small demo of the problem where I use do auth with express + mongo ie. async redux. This is not working as intended. https://youtu.be/Zxm5GOYymZQ
Here's the link of the app where I use hardcoded username and password (both "test") to do auth. No async here. This works as intended. Username and password are both "test". https://poke-zoo.herokuapp.com/
Here's App.js
:
const ProtectedRoute = ({ component: Component, ...rest }) => {
const authState = useSelector(selectorAuth)
// const location = useLocation()
return (
<Route
{...rest}
render={props => {
if (authState.isUserLoggedIn) {
return <Component {...props} />
} else {
return (
<Redirect
to={{
pathname: "/",
state: {
from: props.location,
},
}}
/>
)
}
}}
/>
)
}
const App = () => {
return (
<Router>
<div tw="flex flex-col bg-green-100 min-h-screen">
<Navbar />
<Switch>
<Route exact path="/" component={Landing} />
<ProtectedRoute path="/home" component={Home} />
<ProtectedRoute path="/explore" component={Explore} />
<Route path="*" component={() => "404 Not found."} />
</Switch>
</div>
</Router>
)
}
Here's ModalLogin.js
.
const ModalLogin = props => {
const { loginModalBool, setLoginModalBool } = props
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const dispatch = useDispatch()
const history = useHistory()
const attemptLogin = e => {
e.preventDefault()
dispatch(tryLogin(username, password))
history.push("/home")
}
return (
<div tw="flex flex-col text-center h-full w-64 bg-gray-200 text-gray-900 rounded-lg shadow-lg p-2 md:p-4 lg:p-6">
<div tw="flex flex-row justify-between">
<p tw="text-lg">Login</p>
<button tw="text-sm" onClick={() => setLoginModalBool(!loginModalBool)}>
close
</button>
</div>
<div tw="flex flex-col justify-around my-1">
<form onSubmit={attemptLogin} tw="">
<input
tw="my-1"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="username"
/>
<input
tw="my-1"
value={password}
onChange={e => setPassword(e.target.value)}
type="password"
placeholder="password"
/>
<button
type="submit"
tw="my-1 p-1 rounded bg-gray-800 text-gray-100 hover:bg-gray-900"
>
log in
</button>
</form>
</div>
</div>
)
}
Here's the authSlice.js
.
import { createSlice } from "@reduxjs/toolkit"
import axios from "axios"
const initialState = {
isUserLoggedIn: false,
username: "",
}
export const authSlice = createSlice({
name: "auth",
initialState: initialState,
reducers: {
login: (state, action) => {
const user = action.payload
if (!user) return alert("Login failed. Incorrect username or password.")
state.username = user.username
state.isUserLoggedIn = true
},
logout: (state, action) => {
// window.localStorage.removeItem("loggedInUser")
state.username = ""
state.isUserLoggedIn = false
},
signup: (state, action) => {
const user = action.payload
state.username = user.data.username
state.isUserLoggedIn = true
},
},
})
export const tryLogin = (username, password) => {
return async dispatch => {
try {
const response = await axios.post("/api/auth/login", {
username: username,
password: password,
})
const user = {
token: response.headers["auth-token"],
username: response.data.username,
}
// window.localStorage.setItem("token", response.headers["auth-token"])
dispatch(login(user))
} catch (e) {
alert("Incorrect Username/Password.")
}
}
}
export const selectorAuth = state => state.auth
export const { login, logout } = authSlice.actions
export default authSlice.reducer
Am I using react-router with redux-toolkit incorrectly?
Here's the Github repo