Use a Username in a Path to Route a Component (React-router-dom) - react-router-dom

I am having a hard time setting up my react-router so that when the path matches the user's username, the userProfile component will be routed and show individually. For example, when the URL is http://localhost:3000/myusername, the userProfile component will only show. I'm kind of confused on how it will work if someone just pastes the entire link instead of being directed to someone's page through the UI.
<Switch>
<Route path="/" component={userProfile} />
<PrivateRoute exact path="/test2" component={test2} />
<PrivateRoute exact path="/test3" component={test3} />
</Switch>
Any help would be appreciated!

You can use this method and access to username in test3 component and handle getting data and showing this page
<Switch>
<Route path="/" component={userProfile} />
<PrivateRoute exact path="/test2" component={test2} />
<PrivateRoute exact path="/:username" component={test3} />
</Switch>

I found that if you just use /:id in the path, then the path extension will pass automatically down to the userProfile component when you use the const {id} = useParams() function in the userProfile component. Then I passed the _id down as a prop from the userProfile component to the Info component so that it can be used to automatically fetch data in a useEffect() and redux dispatch() function. Oh and also, the <Route path="/:id" component={userProfile} /> needs to be an exact path and must go to the bottom of the Route Switch list so that it doesn't get picked first.
<Switch>
<PrivateRoute exact path="/test2" component={test2} />
<PrivateRoute exact path="/test3" component={test3} />
<Route exact path="/:id" component={userProfile} />
</Switch>
const Profile = () => {
const { id } = useParams();
return (
<div>
<Info _id={id} />
</div>
);
};
export default Profile;
const Info = (props) => {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getProfileInfo(props._id));
}, []);
return (
<div></div>
);
};
export default Info;

Related

React-router doesn't work well when loaded from a route instead of the home page

We're using react 16.13 and react-router-dom 5.1.2 but we struggle to make it work the way we want:
it works great when used with our https://react.domain.com/
but it doesn't when a user starts the app directly on a subpage, https://react.domain.com/page1 as we can't find any way to tell react-router that the base url is still / and not page1/
(We've configured the nodejs/express backend to send the react app no matter the route)
So react-router just adds all the history / path to the /page1 url, resulting in /page1/login, /page1/page1, etc. instead of the /login or /page1 urls.
Is there any way to achieve that?
The goal is to allow the refresh of the page, and to allow direct access to a specific route.
EDIT: code example
client side
<StoreProvider store={store}>
<Suspense fallback={<MainPageFallback />}>
<ThemeProvider theme={theme}>
<Router basename={location.pathname}>
<I18nextProvider i18n={i18next}>
<TryCatch>
<Navbar actions={<UserSettings />} />
<div className={classes.appContent}>
<Switch>
<Route exact path="/start">
<LandingPage />
</Route>
<Route exact path="/search">
<SearchPlacePage />
</Route>
<Route exact path="/signup">
<SignUpPage />
</Route>
<Route exact path="/signin">
<LoginPage />
</Route>
<Route exact path="/forgot_password" component={ForgotPassword} />
<Redirect from="/*" to="/start" />
</Switch>
<Snackbar />
</div>
</TryCatch>
</I18nextProvider>
</Router>
</ThemeProvider>
</Suspense>
</StoreProvider>
server side
#Route('/*')
public async home({ query }: Request, res: Response) {
const { resolve } = await import('path');
const { readFileAsync } = await import('../Infrastructure/readFileAsync');
try {
const file = (await readFileAsync(resolve(__dirname, '..', '..', '..', 'static', 'index.html')))
.toString('utf-8');
return res.send(file);
} catch (err) {
return res.sendFile(resolve(__dirname, '..', '..', '..', 'static', 'notFound.html'));
}
}
You need to use Routes rather than Switch for react-router-dom#6. Something like this:
<BrowserRouter>
<Routes>
<Route path="/" element={<App />}>
</Route>
</Routes>
</BrowserRouter>

When i go to dashboard route i want to show my hamburger icon [duplicate]

I am having trouble writing code to render a login page with no navbar and sidebar. I have come across some pages that ask similar questions but none seem to pertain to my current situation.
How to hide navbar in login page in react router
the example given is great but I believe the way of accomplishing that same task has changed with react-router-dom v6 leading me to read about this change in https://dev.to/iamandrewluca/private-route-in-react-router-v6-lg5
It seems I am not understanding a certain aspect about routing with React Router. In the code below I have two Routes. One of the routes(Login) I would like to have render without the NavBar and SideBar component.
const App = () => {
return (
<>
<Routes>
<Route path="/login" element={<LoginPage />} />
</Routes>
<NavBar />
<SideBar />
<main className={styles["main--container"]}>
<div className={styles["main--content"]}>
<Routes>
<Route path="/" element={<Dashboard />} />
</Routes>
</div>
</main>
</>
);
};
An alternative, that I also tried, would be to move the NavBar and SideBar tags into the Dashboard component, but then I would essentially have to do the same copy and paste for any new components. This method felt wrong and inefficient , but if this is the correct way of doing it I will do the needful
Edit: I think it's important to include what it currently does is load the Login page with the NavBar and SideBar included. Navigating to the dashboard component has the NavBar and SideBar but this is intended.
What I would like is for the Login page not to have the NavBar and SideBar
If I understand your question, you are wanting to render the nav and sidebar on the non-login route. For this you can create a layout component that renders them and an outlet for the nested routes.
Using nested routes
import { Outlet } from 'react-router-dom';
const AppLayout = () => (
<>
<NavBar />
<SideBar />
<main className={styles["main--container"]}>
<div className={styles["main--content"]}>
<Outlet /> // <-- nested routes rendered here
</div>
</main>
</>
);
const App = () => {
return (
<>
<Routes>
<Route path="/login" element={<LoginPage />} />
<Route element={<AppLayout />} >
<Route path="/" element={<Dashboard />} /> // <-- nested routes
</Route>
</Routes>
</>
);
};
Using a routes configuration and useRoutes hook
const routesConfig = [
{
path: "/login",
element: <LoginPage />,
},
{
element: <AppLayout />,
children: [
{
path: "/",
element: <Dashboard />,
},
],
},
];
...
import { useRoutes } from 'react-router-dom';
const App = () => {
const routes = useRoutes(routesConfig);
return routes;
};
Using a routes configuration and data routers (introduced in v6.4.0)
const routesConfig = [
{
path: "/login",
element: <LoginPage />,
},
{
element: <AppLayout />,
children: [
{
path: "/",
element: <Dashboard />,
},
],
},
];
...
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
const router = createBrowserRouter(routesConfig);
const App = () => {
return <RouterProvider router={router} />;
};
The easiest way for you to hide the navbar would be to go to the login page component and call useLocation(). Then you woulf do something like this after declaring the use location. And assigning it to a variable location
{ location.pathname === "/login" ? null : (
Render the whole navbar component);
Not sute if you can be able to read as I type from my phone

react router dom 6^. Unable to route Dynamically

I am having trouble with dynamic routing in
react-router-dom.
Whenever I go to the dynamic page I get a white screen. Only error message is
The resource from localhost:8082/individuals/bundle.js was blocked due to MIME type(“text/html”) mismatch (X-Content-Type-Options: nosniff).
I have research countless articles and have been unable to find a solution.
Every Other static Component Works and is able to pull from the api.
The API I am pulling from is able to dynamically display products.
"http://localhost/40"
will display the object with the id of 40 in json format. Node.js express Api
Thank you for your time
Route Component
function Rout(){
return(
<div>
<BrowserRouter>
<Menu/>
<div className="page">
<Routes>
<Route index element={<MainContent />} />
<Route path="/products" element={<Product />} />
<Route path='/individuals/:id' element={<Individualproduct />} />
<Route path="/about/" exact element={<About />} />
<Route path="/shippingandreturns" element={<Shipping />} />
</Routes>
</div>
</BrowserRouter>
</div>
)
}
export default Rout
Dynamic Component
const Individualproduct = () => {
const { id } = useParams();
const [products, setProducts] = useState([]);
const url = 'http://192.168.1.91:4001/';
useEffect(()=>{
async function getProduct(){
const response = await axios.get(`${url}/${id}`);
const a = (response.data.Results)
console.log(a)
setProducts(a)
}
getProduct()
}, [])
return (
<article>
{
products.map((item)=>{
<h1>{item.id}</h1>
})
}
</article>
);
};

Protect routes in react with server side rendering

I have a react app and I serving it with Node js. I currently have a jwt token implemented in node js. So, when I login a token is sent back to the client and then stored in localstorage.
To verify that the user is logged in and has rights to access some of the pages. I will need to
Get the token from local storage
Check the expiry of the token. And if it is expired redirect them back to the login page.
I currently cannot get passed the 1st step
Here is what I have
private-route.js
function PrivateRoute({ component: Component, ...rest }) {
const [token, setToken] = useState();
useEffect(() => {
setToken(localStorage.getItem("usr-sess"));
console.log(token);
}, [token]);
return (
<Route
{...rest}
render={props =>
token ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
}
export default PrivateRoute;
app.js
<Switch>
<Route exact path="/login" component={LoadableLogin} />
<PrivateRoute eexact path="/test" component={LoadableTestPage} />
<Route component={LoadableNotFound} />
</Switch>
server.tsx
const jsx = renderToString(
<ApolloProvider client={clientConfig}>
<Loadable.Capture report={moduleName => modules.push(moduleName)}>
<StaticRouter context={context} location={req.url}>
<App />
</StaticRouter>
</Loadable.Capture>
</ApolloProvider>
);
I constantly keep being redirected back to login even when the token is there.
The issue is that it takes a bit of time to setToken() and by then it will redirect me back to login. Is there any way to do this?
Not using useEffect and doing
localStorage.getItem("usr-sess") ? (
<Component {...props} />
) : (
<Redirect to="/login" />
)
throws a localStorage undefined error, I can't think of anything else to do.

Child route handled by the same parent's component using react router

I'm trying to define the routes for a paginated application.
/ -> handled by App
/page/:page -> also handled by App
These are what my routes look like:
var routes = (
<Route name="app" path="/" handler={App}>
<Route name="paginated" path="page/:page" handler={App} />
</Route>
);
This is what App looks like:
var App = React.createClass({
render : function() {
return (
<div>
<RouteHandler/>
Something...
</div>
);
}
});
The problem here is that, as paginated is an app's child route, that Something... in the componet gets rendered twice.
What I'm trying to acomplish here is to default to page 1 for the app route and to load the desired page for the paginated route, without loading twice.
Any way to do this?
Using the App handler twice works the way you expect - it calls Apptwice. However, the parent should only be used as the parentRoute Handler, and the children use their ownHandlers`.
To get the initial page to load properly, use a DefaultRoute for the base path:
routes
var routes = (
<Route name="app" path="/" handler={App}>
<DefaultRoute handler={Home}/>
<Route name="paginated" path="page/:page" handler={Page} />
</Route>
);
app
var App = React.createClass({
render : function() {
return (
<div>
<RouteHandler/>
</div>
);
}
});
home
var Home = React.createClass({
render : function() {
return (
<div>
...Something...
</div>
);
}
});
page
var Page = React.createClass({
render : function() {
return (
<div>
...Something Completely Different...
</div>
);
}
});
The React Router Default Handler Docs have a more substantial example:
<Route path="/" handler={App}>
<!--
When the url is `/`, this route will be active. In other
words, `Home` will be the `<RouteHandler/>` in `App`.
-->
<DefaultRoute handler={Home}/>
<Route name="about" handler={About}/>
<Route name="users" handler={Users}>
<Route name="user" handler={User} path="/user/:id"/>
<!-- when the url is `/users`, this will be active -->
<DefaultRoute name="users-index" handler={UsersIndex}/>
</Route>
</Route>
Notice here that <Route name="user" handler={User} path="/user/:id"/> also has a default route, so when there is no :id match it has somewhere to go.
Hope this helps!
At the end I came up with a solution using a redirection that allowed me to have the pagination and nested routes in the paginated one.
var routes = (
<Route name="app" path="/" handler={App}>
<Redirect from="/" to="paginated" params={{ page : 1 }} />
<Route name="paginated" path="page/:page" handler={PaginationLoader} />
</Route>
);

Resources