I have upgraded to react-router v4, React v16, react-router-redux v5.0.0-alpha.9. After going through the tutorials in internet I finally end up with configuring my routes, Redux store and history as like below but the routes are not working. If I click on login/register or other links it is taking me to NotFound component always.
I am very new to these latest versions.
Routes.js
import React from 'react';
import {default as history} from './history';
import { Switch, Redirect, IndexRedirect, IndexRoute, BrowserRouter as Router, Route, Link } from 'react-router-dom';
import {Provider} from 'react-redux';
import store from './store'
import {Map, toJS} from 'immutable';
import TransparentIndexPage from './Navigation/Components/TransparentIndexPage'
// Import miscellaneous routes and other requirements
import App from './App';
import NotFound from './Layout/Components/NotFound';
// Import static pages
import Home from './Layout/Components/Home';
import Contact from './Contact/Components/Contact';
import Settings from './Navigation/Components/Settings';
import CreatePage from './CreatePage/Components/CreatePage';
import {getCurrentUser, extractRoleInfo} from './Login/utils'
import Careers from './About/Components/Careers';
import Team from './About/Components/Team';
import Press from './About/Components/Press';
import Policy from './About/Components/Policy';
// import About from './About/Components/About';
// Import authentication related pages
import Login from './Login/Components/Login';
import ProfileView from './MyProfile/Components/ProfileView';
import Confirmation from './Email/Components/Confirmation';
import About from './About/Components/About';
import Register from './Register/Components/Register';
// import Facebook from './Facebook/Components/FacebookLogin';
import Logout from './Logout/Components/Logout';
import Profile from './Profile/Components/Profile';
// import UserDropdown from './Layout/Components/UserDropdown';
import ForgotPassword from './ForgotPassword/Components/ForgotPassword';
import ResetPassword from './ResetPassword/Components/ResetPassword';
import {syncHistoryWithStore} from 'react-router-redux'
// Import dashboard pages
import Dashboard from './Dashboard/Components/Dashboard';
import Search from './Search/Components/Search';
import Post from './Post/Components/Post';
import * as loginActions from './Login/actions';
import { ConnectedRouter, routerReducer, routerMiddleware } from 'react-router-redux'
// const history = createHistory();
// const history = syncHistoryWithStore(browserHistory, store, {
// selectLocationState: state => state.get('Routes').toJS()
// })
// console.log("History: ", JSON.stringify(history));
function redirectIfAuth(nextState, replace) {
const user = getCurrentUser(store.getState())
if (user.get('id')) {
replace({
pathname: 'dashboard',
state: { nextPathname: nextState.location.pathname}
})
}
}
var update = 0
function checkRoles(nextState, replace) {
const user = getCurrentUser(store.getState())
console.log("Role extract user: ", JSON.stringify(extractRoleInfo(user.get('role'))))
if (!extractRoleInfo(user.get('role'))) {
var url = window.location.href
var refURL = ''
let x = window.location.href.split('/')
for(let v=5; v<x.length; v++)
{
refURL += x[v]
}
if(refURL)
{
if(update == 0)
{
update = 1
store.dispatch(loginActions.setURL(refURL))
}
}
replace({
pathname: '/login',
state: { nextPathname: nextState.location.pathname }
})
}
}
const routes = (
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<Route exact path="/" component={App} />
<Switch>
<Route path="login" component={Login} onEnter={redirectIfAuth}/>
<Route path="contact" component={Contact} />
<Route path="home" component={Home} />
<Route path="about" component={About} />
<Route path="careers" component={Careers} />
<Route path="press" component={Press} />
<Route path="policy" component={Policy} />
<Route path="team" component={Team} />
<Route path="home" component={Home} />
<Route path="register" component={Register} />
<Route path="about" component={About} />
<Route path="forgotpassword" component={ForgotPassword} onEnter={redirectIfAuth}/>
<Route path="resetpassword/:resetToken" component={ResetPassword}/>
<Route path="confirmation/:token" component={Confirmation} />
<Route path="dashboard" name='Dashboard' component={Dashboard} onEnter={checkRoles}/>
<Route path="/:id/myProfile" name='ProfileView' component={ProfileView} onEnter={checkRoles}/>
<Route path="create-page" name='ProfileView' component={CreatePage} onEnter={checkRoles}/>
<Route path="/:id/profile" name='Profile' component={Profile} onEnter={checkRoles}/>
<Route path=":loginId" name="NT" component={TransparentIndexPage} onEnter={checkRoles}>
<Switch>
<Route path="post" name='Post' component={Post} />
<Route path="search" component={Search} />
<Route path="settings" component={Settings} />
</Switch>
</Route>
<Route path="*" component={NotFound}/>
</Switch>
</div>
</ConnectedRouter>
</Provider>
)
export default routes
history.js
import createBrowserHistory from 'history/createBrowserHistory';
import createMemoryHistory from 'history/createMemoryHistory';
export default process.env.BROWSER ? createBrowserHistory() : createMemoryHistory();
store.js
/*eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }]*/
import {Map} from 'immutable';
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducer';
import browserStorage from './browserStorage';
import { routerReducer, routerMiddleware, push } from 'react-router-redux';
import {default as history} from './history';
const middlewareHistory = routerMiddleware(history);
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
//sessionmiddleware is not required as we are using jsonwebtoken
const sessionMiddleware = _store => next => action => {
let result = next(action)
switch(action.type) {
case 'LOGIN_SUCCESS':
browserStorage.set({
realUser: {
loginId: action.user.id,
token: action.token
},
currentUser: {
loginId: action.user.id,
token: action.token
}
})
break;
case 'USER_LOGOUT_SUCCESS':
localStorage.clear()
break;
default:
break;
}
return result
}
const store = createStore(
reducer,
Map(),
composeEnhancers(
applyMiddleware(
sessionMiddleware,
middlewareHistory,
thunk
),
window && window.devToolsExtension ? window.devToolsExtension() : f => f
)
);
export default store;
Did you try to put a "/" before your route names like :
<Route path="/contact" component={Contact} />
Related
I have a problem with the router V6. The routes are not being rendered. The homepage use to have all the products and now I cannot see any of the products shown, also I have my code to the links that go to every part of the website but is not appearing. The error that appears is:
react_devtools_backend.js:4045 No routes matched location "/rewards-store-andrea-lopez-bravo"
at Routes (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:32538:5)
at Router
at div
at App (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/main.chunk.js:423:63)
at Router (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:32471:15)
at BrowserRouter (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/vendors~main.chunk.js:31958:5)
at AppProvider (http://localhost:3000/rewards-store-andrea-lopez-bravo/static/js/main.chunk.js:4188:5)
index.tsx:25 No routes matched location "/rewards-store"
This my router:
import { Routes, Route } from "react-router-dom";
import { Home } from "../pages/Home";
import { History } from "../pages/History";
import { Points } from "../pages/Points";
import { NotFound } from "../components/notification/NotFound";
export const Router = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
</Routes>
);
};
This is index:
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import AppProvider from "./context/AppContext";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<AppProvider>
<BrowserRouter>
<App />
</BrowserRouter>
</AppProvider>
</React.StrictMode>,
document.getElementById("root")
);
AppContext:
import React,{ useState } from "react";
import { usePagination } from "../components/utils/pagination.jsx";
export const AppContext = React.createContext();
export default function AppProvider({ children }) {
const [user,setUser] = useState({})
const [points, setPoints] = useState(0)
const [products, setProducts] = useState([])
const [reedemStatus, setReedemStatus] = useState({})
const [history, setHistory] = useState([])
const paginationList = usePagination(products, 16)
const paginationHistoryList = usePagination(history, 16)
const totalProducts = products.length
const totalHistory = history.length
const handlerAddPoint =(value)=>{
const newUser = {...user}
newUser.points = user.points + value
setUser(newUser)
}
const handlerSubtractPoint =(points)=>{
const newUser = {...user}
newUser.points = user.points - points
setUser(newUser)
}
return(
<AppContext.Provider value={{user,
setUser,
handlerAddPoint,
handlerSubtractPoint,
points,
setPoints,
products,
setProducts,
totalProducts,
paginationList,
reedemStatus,
setReedemStatus,
history,
setHistory,
paginationHistoryList,
totalHistory}}>
{children}
</AppContext.Provider>
);
}
App.js
import React, { useEffect, useContext } from "react";
import "./App.css";
import { Header } from "./components/header/Header";
import { Nav } from "./components/nav/Nav.jsx";
import { getUser } from "./services/users";
import { AppContext } from "./context/AppContext";
import { Notification } from "./components/notification/Notification";
import { Router } from "./routers/Router";
function App() {
const { setUser } = useContext(AppContext);
useEffect(() => {
getUser().then((user) => {
setUser(user);
});
}, [setUser]);
return (
<div className="App">
<Notification />
<Nav />
<Header />
<Router />
</div>
);
}
export default App;
In the menu.jsx the links are not rendering:
import "./Menu.css";
import React from "react";
import { Link } from "react-router-dom";
export const Menu =()=>{
return(
<ul className="menu flex-row">
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/">Home</Link></li>
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/points">Add points</Link></li>
<li className="pink-line"><Link className="normal-text" to="/acamica-rewards-store/history">History</Link></li>
</ul>
)
}
In your router always put the home route at the very bottom!
<Routes>
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
<Route path="/" element={<Home />} />
</Routes>
or make sure to make the home path as exact!
<Routes>
<Route exact path="/" element={<Home />} />
<Route path="/history" element={<History/>}/>
<Route path="points" element={<Points/>}/>
<Route path="NotFound" element={<NotFound/>} />
</Routes>
I did this in v.6
<Route path="/cart" element={<CartPage />}>
<Route path=":id" element={<CartPage />} />
</Route>
Protected Routes.js:
In protected routes you can see I'm using directly false in if statement but I'm still able to see that page why?
import React from 'react';
import { Route } from 'react-router-dom';
// import Auth from './User/Auth';
import Error401 from './Error/401';
// create a component for protected route
console.log('Routes.js');
export const ProtectedRoute = ({ element: Element, ...rest }) => {
console.log("Function Called")
return (
<Route {...rest} render={props => {
if(false){
return <Element {...props} />
}else{
return <Error401 />
}
}
} />
)
}
App.js:
This is app.js where I'm using protected routes component
import './App.css';
import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { Layout } from 'antd';
import { MoneyCollectOutlined } from '#ant-design/icons';
import Login from './Components/User/Login';
import Signup from './Components/User/Signup';
import {ProtectedRoute} from './Components/Routes';
import Error404 from './Components/Error/404';
function App() {
return (
<BrowserRouter>
<Layout style={{minHeight:"100vh"}}>
<Layout.Header>
<h1 style={{color:"white"}} align="center"> <MoneyCollectOutlined/>MoneyG</h1>
</Layout.Header>
<Layout.Content style={{minHeight:"100%"}}>
<Routes>
<ProtectedRoute exact path="/register" element={<Signup/>} />
<ProtectedRoute exact path="/login" element={<Login/>} />
<Route path="*" element={<Error404/>} />
</Routes>
</Layout.Content>
</Layout>
</BrowserRouter>
);
}
export default App;
First, <Routes> elements should only have <Route> elements as children. You should move your protection logic down a layer.
Secondly, the render prop doesn't exist anymore in V6. It was replaced in favor of element. See doc.
Here is how you might tackle it:
<Routes>
<Route exact path="/register" element={(
<ProtectedRoute>
<Signup/>
</ProtectedRoute>
)} />
<Route exact path="/login" element={(
<ProtectedRoute>
<Login/>
</ProtectedRoute>
)} />
<Route path="*" element={<Error404/>} />
</Routes>
And:
const ProtectedRoute = () => {
if (condition) { return <Error401 />; } // You might as well use Navigate here
return children;
};
you can use createContext & useContext
//store/AuthApi.jsx
import { createContext } from "react";
const AuthApi = createContext();
export default AuthApi;
Then define the context app.jsx
import React, from 'react'
import { AllRoutes } from 'routes/Routes';
import { BrowserRouter as Router } from "react-router-dom";
import AuthApi from 'store/AuthApi';
const App = () => {
const [user, setUser] = useState(false);
useEffect(() => {
// you can get user from localStorage or Cookie(js-cookie npm)
//then you can change user state true or false
}, [])
return (
<>
<AuthApi.Provider value={{ user, setUser }}>
<Router>
<AllRoutes />
</Router>
</AuthApi.Provider>
<Toast />
</>
)
}
export default App
then see AllRoutes
//routes/Routes
import React, { useContext } from "react";
import { Routes, Route } from "react-router-dom";
import { SignIn, SignUp, Dashboard } from "pages";
import AuthApi from "store/AuthApi";
export const ProtectedRouting = () => {
return (
<Routes >
<Route path='/' exact element={<Dashboard />} />
// add more protected routes
</Routes>
)
}
export const AuthRouting = () => {
return (
<Routes >
<Route exact={true} path='/sign-in' element={<SignIn />} />
<Route exact={true} path='/sign-up' element={<SignUp />} />
</Routes>
)
}
export const AllRoutes = ()=> {
const context = useContext(AuthApi);
console.log(context.user)
return (
context.user ?
<ProtectedRouting />
: <AuthRouting />
)
}
pages/SignIn.jsx
import React,{ useContext } from 'react';
import AuthApi from "store/AuthApi";
const SignIn = () => {
const context = useContext(AuthApi);
const signInSubmit =(e)=> {
e.preventDefault();
//post request to signin
// if login is successfull then save user or token in cookie or localStorage or something
context?.setUser(true);
//...
}
return (
//signin code here
<form onSubmit={signInSubmit}>
///input here
</form>
)
}
export default SignIn
I am using private route in my app to access dashboard. if I am not logged in it worked correctly and redirect me to the sign in page. but even if I am logged in it does not gives access to dashboard. Here is my code.
App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './containers/Home';
import Login from './containers/Login';
import Dashboard from './containers/Dashboard';
import PrivateRoute from './components/PrivateRoute';
import { Provider } from 'react-redux';
import store from './store';
const App = () => (
<Provider store={store}>
<Router>
<Layout>
<Switch>
<Route exact path='/' component={Home} />
<PrivateRoute exact path='/dashboard' component={Dashboard} />
<Route exact path='/login' component={Login} />
</Switch>
</Layout>
</Router>
</Provider>
);
export default App;
PrivateRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
const PrivateRoute = ({ component: Component, auth, ...rest }) => (
<Route
{...rest}
render={(props) => {
if (!auth.isAuthenticated) {
return <Redirect to="/login" />;
} else {
return <Component {...props} />;
}
}}
/>
);
const mapStateToProps = (state) => ({
auth: state.auth,
});
export default connect(mapStateToProps)(PrivateRoute);
And if I am logged in on react redux tool my states are these
I noticed even if isAuthanticated becomes true after login but else part of privateRoutes.js never called
I have an app that uses styled-components and material-ui. I have private routes configurated, based on the user role and if the user is not authenticated I should return him to login page. But when that happen the layout do no load.
App.tsx
import React from 'react';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core';
import { Provider } from 'react-redux';
import { ToastContainer } from 'react-toastify';
import { PersistGate } from 'redux-persist/integration/react';
import { ThemeProvider as StyledThemeProvider } from 'styled-components';
import Routes from './routes';
import { configureStore } from './store/configure-store';
import GlobalStyle from './styles/globalTheme';
import defaultTheme from './styles/theme/default.theme';
const { store, persistor } = configureStore();
const theme = createMuiTheme({});
function App() {
return (
<Provider store={store}>
<MuiThemeProvider theme={theme}>
<StyledThemeProvider theme={defaultTheme}>
<PersistGate loading={null} persistor={persistor}>
<GlobalStyle />
<Routes />
<ToastContainer />
</PersistGate>
</StyledThemeProvider>
</MuiThemeProvider>
</Provider>
);
}
export default App;
routes.tsx
import React, { memo } from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import NotFound from '../components/NotFound';
import Dashboard from '../pages/Dashboard';
import Login from '../pages/Login';
import Register from '../pages/Register';
import { ProtectedRoute } from './permissions-route';
function Routes() {
return (
<BrowserRouter>
<Switch>
<ProtectedRoute
path="/dashboard"
component={Dashboard}
requiredRole={['USER']}
/>
<Route exact path="/" component={Login} />
<Route exact path="/login" component={Login} />
<Route exact path="/cadastro" component={Register} />
<Route exact path="/error" component={NotFound} />
</Switch>
</BrowserRouter>
);
}
export default memo(Routes);
permission-route.tsx
import React from 'react';
import { useSelector } from 'react-redux';
import { Route, Redirect } from 'react-router-dom';
import { RootState } from '../store/configure-store';
interface Teste {
path: any;
component: any;
render?: any;
requiredRole: any;
}
export const ProtectedRoute = ({
path,
component: Component,
render,
requiredRole,
...rest
}: Teste) => {
const userRole = useSelector((state: RootState) => state.user.role);
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
return <Redirect to="/login" />;
}}
/>
);
};
export default ProtectedRoute;
What happens after redirect occurs
Instead of returning the <Redirect /> component, try window.location.href = "/login";
return (
<Route
path={path}
{...rest}
render={(props) => {
if (requiredRole.includes(userRole)) {
return Component ? <Component {...props} /> : render(props);
}
window.location.href = "/login";
}}
/>
);
This should refresh the page and make it get the proper stylings again
I had a similar issue using MUI and Router.
I found that I was importing different versions of MUI: #mui and #material-ui after replacing #material-ui components and uninstalling it, the issue was resolved.
Most likely this is an issue with conflicting styling.
I suggest checking browser DevTools to see what files/classes are overriding these styles after redirect.
I am working on rerouting my application. I have a form, I want the user to be redirected after the form is submitted successfully. I placed the logic after the api is successful. My url changes but the component that is meant to be loaded on that url does not load.
import { browserHistory } from '../router/router';
...
export const storeRecord=(data)=>{
return function(dispatch, getState){
//console.log('state',getState());
const {authToken, userId} = getState().authReducer;
token= authToken;
data.userId = userId;
const url = 'investment/store';
apiCall(url, data, dispatch,'post').then((data)=>{
try{
if(data.status=== 200){
//let data = apiResponse.data
console.log('success',data);
browserHistory.push('/');
//dispatch(push('/'));
}
}
catch(error){
console.log('returnedError',error);
}
}, (error)=>{console.log(error)});
}
}
Here is my route as well:
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { createBrowserHistory } from 'history';
...
export const browserHistory = createBrowserHistory();
const AppRouter=()=>{
return(<Router>
<LoaderModal />
<Switch>
<Route path="/" exact component={LandingPage} />
<PublicRouter path="/register" exact component={SignupPage} />
<PublicRouter path="/login" exact component={LoginPage} />
<PrivateRoute path="/investment/new" exact component={InvestmentForm} />
<Route component={NotFoundPage} />
</Switch>
</Router>)
}
export default AppRouter;
I am using react-router-dom for rerouting and history for the browser re-routing.
You can use following code in place of dispatch(push('/')) which you used in storeRecord component.
window.location.assign('/');
You need to use the same history object that your Router modules uses to dynamically Route.
The easiest solution is for you to not use browserRouter but to use a Router with custom history
import React from 'react';
import { Router, Route, Switch } from 'react-router-dom';
import { createBrowserHistory } from 'history';
...
export const browserHistory = createBrowserHistory();
const AppRouter=()=>{
return(<Router history={browserHistory}>
<LoaderModal />
<Switch>
<Route path="/" exact component={LandingPage} />
<PublicRouter path="/register" exact component={SignupPage} />
<PublicRouter path="/login" exact component={LoginPage} />
<PrivateRoute path="/investment/new" exact component={InvestmentForm} />
<Route component={NotFoundPage} />
</Switch>
</Router>)
}
export default AppRouter;
and then your action will look like
import { browserHistory } from '../router/router';
...
export const storeRecord=(data)=>{
return function(dispatch, getState){
const {authToken, userId} = getState().authReducer;
token= authToken;
data.userId = userId;
const url = 'investment/store';
apiCall(url, data, dispatch,'post').then((data)=>{
try{
if(data.status=== 200){
browserHistory.push('/');
}
}
catch(error){
console.log('returnedError',error);
}
}, (error)=>{console.log(error)});
}
}