I'm writing a chat application in Django and using React as the front end, I'm serving the react at root path 'localhost:8000/' and there are some path in the react app too such as 'chat/:user', I can access this as long as I go from the root path, if I enter the path manually or try reloading the page it gives the error 'Page not found'.
This is my urls.py file
from django.contrib import admin
from django.urls import path, include
from django.views.generic import TemplateView
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
path('', TemplateView.as_view(template_name='index.html'), name='chat'),
path('api-auth/', include('rest_framework.urls'), name='api-auth'),
path('api/', include('api.urls')),
]
and this is my App.js
function App(props) {
const [user, setUser] = useState('none');
useEffect(() => {
fetch('http://localhost:8000/api/user-data')
.then((response) => response.json())
.then((data) => {
setUser(data.username);
});
}, [])
//console.log(window.location.href);
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Layout user={user} socket={props.socket} />}>
<Route index element={<Home user={user} socket={props.socket} />} />
<Route path='chat/:chattingUser' element={<ChatPage user={user} socket={props.socket} />} />
<Route path='search/:queryText' element={<SearchPage user={user} socket={props.socket} />} />
</Route>
</Routes>
</BrowserRouter>
);
}
I was at the route /chat/ and I changed some things in the code so had to reload the page, then this error came, why is it looking at django urls when i reload and how do I make it look at react when reloading or entering urls manually.
I haven't implemented it yet but I want my app to stay on the react side once the user is authenticated and only come to the django pages only when it logs out.
Related
I have my routes setup like this:
<Route path={`/home`} element={<PrivateRoute />}>
<Route
index={true}
element={<Home />}
/>
<Route path={`settings`} element={<Settings />} />
</Route>
Here, I want to redirect the user back to the root (/home) when the user has opened /home/settings directly from the browser. That is, I do not want the user to open any of the children routes before opening the parent route.
Note: This does not have to do anything with authentication.
This is what I've tried:
In PrivateRoute component, I've used a context to store the pathnames that the user has visited. And each time a page is opened, I check if the /home path exists. If it doesn't, I route the user to /home.
But I feel this is extremely bad for code maintainability and also might not be the right way to do it.
Instead of storing and checking all the paths a user has visited you could just store a boolean state of the "/home" path has been visited. I'd suggest using a couple layout routes, one to provide a homeVisited state and a callback to update the state. One layout route provides the context while the other layout handles the redirection to "/home" if it has not been visited yet.
Example:
const HomeCheckProviderLayout = () => {
const [visited, setVisited] = React.useState();
const visitedHome = () => setVisited(true);
return <Outlet context={{ visited, visitedHome }} />;
};
const HomeCheckLayout = () => {
const { visited } = useOutletContext();
return visited ? <Outlet /> : <Navigate to="/home" replace />;
};
The Home component uses the useOutletContext hook to access the visitedHome to trigger in a useEffect hook.
const Home = () => {
const { visitedHome } = useOutletContext();
React.useEffect(() => {
visitedHome();
}, [visitedHome]);
....
};
Routing configuration:
<Routes>
<Route element={<PrivateRoute />}>
<Route path="/home" element={<HomeCheckProviderLayout />}>
<Route index element={<Home />} />
<Route element={<HomeCheckLayout />}>
<Route path="settings" element={<Settings />} />
... other routes that should redirect to `"/home"` if unvisited yet ...
</Route>
</Route>
... other protected routes ...
</Route>
... other routes ...
</Routes>
I am using React for my webapp frontend . But during development , i came across routing problem in react-router-dom V6 . That problem is i would like to show 404 error page if none of the routes is matched . Here is my code ,
import React from 'react';
import { BrowserRouter,Routes,Route} from 'react-router-dom';
import Home from "./Pages/Home"
import Allposts from './Pages/Allposts'
import Createpost from './Pages/Createpost'
import Error404 from './Pages/Error404'
const App = () => {
return(
<>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />}/>
<Route path="/all-posts" element={<Allposts />}/>
<Route path="/create-post" element={<Createpost />} />
<Route path="*" element={<Error404 />} />
</Routes>
</BrowserRouter>
</>
)
}
export default App;
As you can see i have added catch all routes Route at the end with path equal to "*" mark . This catches all routes except the nested routes (and this is the problem ) . By general rule , it should catch all routes whether that is nested or not nested and it should display that 404 error page component . When i am using route "localhost:3000/all-posts/12345" <--- as this route is not present it should display that 404 error page component instead of showing this it shows a just blank page and an error pops out in console saying resource not found with an error of 404 that's it .
This is the problem . How to solve this problem and show 404 error page component .
Hi did you try ?
Try this
<Switch>
<Route path='*' component={Error404} />
</Switch>
react can't check on it's own if the post exists or not,
you can put a simple check like this to handle it
if (post exists) {
return <Post/>; //render Post info/details
} else {
return <Error404 />; // if not redirect to 404
}
If you could switch to this method, it would work for all the nested components as well.
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
function Error404() {
return <h2>404 Not found</h2>;
}
const router = createBrowserRouter([
{
path: '/',
errorElement: <Error404 />,
children: [
{path: '', element: <Home /> },
{path: 'all-posts', element: <Allposts /> },
{path: 'create-post', element: <Createpost /> },
],
},
]);
function Router() {
return (
<RouterProvider router={router} />
);
}
export default Router;
Quick question here, I have the below code, and I want to be able to import a whole lot of routes from my package. The routes that are imported should be controlled by the package I'm building. If I add a new page in the package (say, ForgotPassword), then I won't want to come here and manually add an entry for ForgotPassword... It should just start working when I update to the latest version of the package.
Also, what will this route collection look like in my package project?
Any ideas welcome :D
...
import { RouteCollectionFromPackage } from "#my/package";
...
<Router basename="/">
<Suspense fallback={<div>Loading...</div>}>
<Switch>
{ /* I WANT TO IMPORT A COLLECTION OF ROUTES FROM MY PACKAGE */}
<RouteCollectionFromPackage />
{ /* THESE ARE IN MY APP */}
<Route exact path="/" component={home} />
<Route exact path="/search" component={search} />
</Switch>
</Suspense>
</Router>
Thanks!!
EDIT:
This is what I have tried, after following some of the suggestions below:
In my module:
const Routes = [
<Route exact path="/Login" component={Login} />,
<Route exact path="/ForgotPassword" component={Login} />,
<Route exact path="/MyProfile" component={Login} />
];
export { Routes };
In my consuming app:
import { Suspense, lazy } from "react";
import { HashRouter as Router, Switch, Route } from "react-router-dom";
import { Routes as PortalFrameworkRoutes, Login} from "#sal/portal";
const home = lazy(() => import("./pages/home/Home"));
const search = lazy(() => import("./pages/search/Search"));
function routes() {
return (
<Router basename="/">
<Suspense fallback={<div>Loading...</div>}>
<Switch>
{PortalFrameworkRoutes.map((route: Route) => route)}
<Route exact path="/" component={home} />
<Route exact path="/search" component={search} />
</Switch>
</Suspense>
</Router>
);
}
export default routes;
I get the error:
Error: Invariant failed: You should not use <Route> outside a <Router>
OR when I use {...PortalFrameworkRoutes} I get:
Spread children are not supported in React
EDIT #2:
This may actually be a crucial bit of information I omitted. In my module, the route is exported, and imported (and again exported) in an index.tsx like this:
export { Routes } from "./routes";
export { Login } from "./pages/login/Login";
I'm not sure if this is 100% correct, but it feels correct since I just want to do an import from the top level of my module, and have everything available there. i.e. import { Routes as PortalFrameworkRoutes, Login } from "#sal/portal";
In your package, export the routes like so:
const yourRoutes = [
<Route ... />,
<Route ... />,
];
export { yourRoutes };
Import it in your consuming application:
import { yourRoutes } from '#your/package';
Then use the array spread operator to include them along the other routes:
<Switch>
{...yourRoutes}
<Route path="/some/application/route" component=... />
</Switch>
In your "#my/package" module, you should export an Array of objects where each object has a path and component property which you can then dynamically render
Then in your current file, you can use the map method to render them
//"#my/package" module
//make sure to import the necessary components you will be adding
import component1 from "//..."
import component2 from "//..."
.
import componentN from "//..."
export myRoutes = [
{path: "/pathToComponent1", component: component1}
{path: "/pathToComponent2", component: component2}
.
{path: "/pathToComponentN", component: componentN}
]
// in your current module
import {myRoutes} from "#my/package"
<Router>
<switch>
...
// where you need to render routes from your module
{myRoutes.map(route => <Route path={route.path} component={route.component}/>}
...
</switch>
</Router>
I've been searching all over the internet for solutions but alas I come here for some help. The problem is that the URL changes but the respective component in Route don't render, instead of that, the NotFoundPage is rendered.
Here's the App.js Router code:
<Router history={history}>
<Switch>
<PrivateRoute exact path="/" component={HomePage} />
<Route path="/login" component={LoginPage} />
<Route path="/register" component={RegisterPage} />
<Route component={NotFoundPage}/>
</Switch>
</Router>
Here's PrivateRoute code:
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={props => (
localStorage.getItem('user')
? <Component {...props} />
: <Redirect to={{ pathname: '/login', state: { from: props.location } }} />
)} />
)
The problem I'm facing is the when I go to / the NotFoundPage is rendered instead of LoginPage but the URL correctly redirects and changes to /login. But when I refresh, the LoginPage is rendered. Similarly, when I click on link that takes to /register from LoginPage the URL changes but RegisterPage doesn't render it's the same NotFoundPage.
During contribution on github we figured solution.
This weird behavior flows from using custom history.
const customHistory = createBrowserHistory();
ReactDOM.render(<Router history={customHistory} />, node);
When it is used then somehow router don't react to changes in a location path.
Until you don't add:
<Switch location={window.location}>
According to the docs the location in switch by default is set to window. location but for some reason when you don't use BroswerRouter or StackRouter but just Router this starts working when we directly set location.
I started to build next website using reactJS and nodejs. The website is required to have minimum 2 languages and it should be possible to share link to website in desired language. I concluded quickly that what i need is to have following url structure
domain.com/en-GB
domain.com/en-GB/gallery
domain.com/en-GB/contact
front end Router:
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
...
<Router>
<React.Fragment>
<Header />
<Suspense fallback={<Loading />}>
<Switch>
<Route exact path="/">
<Landing />
</Route>
<Route path="/gallery">
<Gallery />
</Route>
<Route path="/about-us">
<AboutUs />
</Route>
<Route path="/contact">
<Contact />
</Route>
<Route>
<PageNotFound />
</Route>
</Switch>
</Suspense>
<Footer />
</React.Fragment>
</Router>
...
front end menu:
import { NavLink } from "react-router-dom";
...
<NavLink to="/about-us">
{Lang.resolve("HEADER_MENU_ABOUT_US")}
</NavLink>
...
pieces of webpack config:
...
const extractTextPlugin = new ExtractTextPlugin({
filename: "css/style.[hash:8].css",
allChunks: true
});
module.exports = {
...
output: {
filename: "js/main.[hash:8].js"
}
...
},
...
server routing:
...
const router = express.Router();
let landing = (req, res, next) => {
res.sendFile(path.join(__dirname, "../../index.html")); // html build by webpack
};
router.get("/", landing);
router.get("/:view", landing);
...
I was wondering if there is something already baked into reactJS to allow this or i need to manually append language part of url like: <Route path={_LANG_ + "/gallery"}>.
Probably some adjustments are also needed to the server routing and webpack paths otherwise it will be a problem while loading css, js files domain.com/en-GB/css/style.css.
Maybe someone already fought this idea and could have some tips.
I am not sure how you gonna handle the translations on each component, but if you have different components (according to the language), then an option would be having different "basenames" on your Router:
<BrowserRouter basename="/calendar">
<Link to="/today"/> // renders <a href="/calendar/today">
<Link to="/tomorrow"/> // renders <a href="/calendar/tomorrow">
...
</BrowserRouter>
From the documentation:
https://reacttraining.com/react-router/web/api/BrowserRouter/basename-string
Similar question:
Multiple BrowserRouter Shows Multiple Components