Is there such a thing like sass mixins in react? - reactjs

So I have a react application that involves a lot of routing and this routings are done based on conditions. For example if a user logs in then some of the paths might mean something different than what they would mean if the user wasn't logged in. Here is a simple example.
<Switch>
(this.state.isAuthenticated)?
this.state.game?
<Route path="/game/Game91" render={(props) => <Game91 {...props} games={this.state.allGames} />} />:
<Route path="/game/Game91/" render={(props) => <CreateGame {...props} game="game91" />} />:
<Route exact path="/game/Game91" render={(props) => <LoginForm {...props} onGuestLogin = {this.guestLogin} parentLocation = "/game/Game91" />} />
}
</Switch>
...
So in the above code if a user is authenticated and if the game is choosen then I want the url /game/Game91 to take the user to the Game91 component. If the user is authenticated but a game isnt choosen I want /game/Game91 to take the user to the create game component and so forth. And this has been workign for me for now. I unserstand this might not be the best practice out their, so I would be glad if you share what the best practices are in such scinarios and send me links to more reads. But my main question for now is that what if I have another path like /somepath/to that also means different things like the /game/Game91. To do, that I will have to rewrite all the above code since I can't fit all this in one ternary operator. Hypotetically this is what I would like.
<Switch>
(this.state.isAuthenticated)?
this.state.game?
<Route path="/game/Game91" render={..something..} />
<Route path="/somePath/to" render={..something..} />
:
<Route path="/game/Game91" render={..somethingElse..} />
<Route path="/somePath/to" render={..somethingElse..} />
:
<Route path="/game/Game91" render={..something..} />
<Route path="/somePath/to" render={..something..} />
}
</Switch>
But the above isn't possible because a ternary operators can't return more than one thing. and I cant use if statments beacuse JSX doesn't allow them. So ideally if I could have function that will return this pair of things without wrapping them in any kind of container like you would with scss mixins that would be great. So is there such a thing in react or are there other better ways to do such things?

Generally every page or container should be addressed to only one route path. Instead of changing the component at runtime by checking the flags, you can navigate from one route to another based on your conditions using react hooks.
Note:
This example uses react router v6. If you are using the v5.2 version of react router, then you need to use history api instead of navigate.
useEffect(() => {
if (isAuthenticated) {
if(isGameActive)
navigate('/gaming');
else
navigate('/create-game');
}
else {
navigate('/login');
}
}, [isAuthenticated]);
<Router>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/gaming" element={<Game91 />} />
<Route path="/create-game" element={<CreateGaming />} />
</Routes>
</Router>
react-router v6

Related

React route does not detect nesting routing and ids

I have some React routes that when I nest one route inside another, I need to repeat the route path.
To explain, for example:
<Route
path="admin">
<Switch>
<Route
path="admin/specific/:id"
component={SpecificAdmin} />
<Route
exact
path="admin"
component={AdminPage}>
</Route>
<Route
exact
path="admin/edit/new"
component={EditSpecificAdmin} />
</Switch>
</Route>
I want a page where I can see the list of items, one for adding a new one and another for looking, editing a specific item. So I thought about the paths edit/new and specific/1.
So the routes do not detect when I write specific/1 (the specific id) and not either the admin nesting, so I need to write the admin in each one...
As Tareq aziz said, you can easily have intel in props.
You can create another router to pass easily new value:
// your original component
import AdminRouter from './Admin/Router';
export default () => {
return (
<Route path="admin">
<AdminRouter />
</Route>
);
}
// in ./Admin/Router.js
export default (props) => {
return (
<Switch>
<Route
exact
path={`${props.match.path}/specific/:id`}
component={SpecificAdmin}
/>
<Route
exact
path={`${props.match.path}`}
component={AdminPage}
/>
<Route
exact
path={`${props.match.path}/edit/new`}
component={EditSpecificAdmin}
/>
</Switch>
);
}
I'm not sure though if the order of the routes are correct.
I think you can get your current page's url from props using location.pathname or match.url. You can see my image. Then you may add your nested route after that. Hope it will help you
You may code your path like this way
path=`${this.props.location.pathname}/edit/new`
path=`${this.props.location.pathname}/specific/:id`

React Router render components with /:username or /component/

I am trying to implement a routing structure where a user goes to another user's page or their own when the path is /:username. I also want to render another page with a path /watch or /watch/ .. Facebook has a similar setup where /:username will take you to your page or another user's and /watch/ for example is a page. Is there best practice to achieve this with react-router?
As of now I have something like this..
<Route path="/" exact component={authenticated ? Home : Index} />
<Route path="/watch/" component={Watch} />
<Route path="/:username" exact component={({match}) => {
if(match.params.username === data.Username) {
return <ProfilePage match={match} />
} else {
return <UserPage match={match} />
}
}} />
Now if I got to /watch/ the profile component is being rendered aswell. So :username is going to match all my routes?
As you already deducted, /:username is matching at the same time as /watch/ because both patterns match the URL /watch/.
Thankfully, React Router provides a <Switch> component for cases like this one, where only the first match is rendered:
<Switch>
<Route path="/watch/" component={Watch} />
<Route path="/:username" component={...} />
</Switch>
Now, with the URL /watch/, only the first route is rendered, even though the second one matches too.
If you are using react-router-dom v6, do these:
instead of Switch, you should use Routes
instead of component={<SomeComponent />} property, use element={<SomeComponent />}
Just in case, you can Read this article about upgrading from v5 to v6

React Router v4 dynamic nested routes do not match

I ask this question just want to make sure that I understand the dynamic nested routes in React Router v4 correctly. I want to build a hacker news client similar to this one. But I am bogged down by setting up the dynamic routes.
In React Router v4, if I follow other tutorials on the web using the match object I will have something like this (A super simple one):
const ChildComponent = ({rows, match}) => (
<div>
<ol>
rows.map((row, i) => {
return (
<li key={row.id}>
<a href={row.url}>row.title</a> // topic title
<Link to=`${match.url}/${row.by}`>row.by</Link> // topic author
</li>
)
}
</ol>
<Route path=`${match.url}/:userId` render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
</div>
)};
And when we render the parent component, we usually use something like this for routing:
<Switch>
<Route path="/" render={Home} />
<Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
<Route path="*" render={() => <div>Not Found</div>} />
</Switch>
But this is not ideal for this case, as when I click to view the author's info I need to display a url like this: "http://mysite/user/userid" instead of the current one which is "http://mysite/news/userid".
However, if I change ${match.url}/${row.by} to /user/${row.by} and change ${match.url}/:userId to /user/:userId the route is not recognized in the app. The route begins with /user/ is simply skipped, it will go straight to the app's NotFound route (if there is one), which is in the parent component. Why will the links in child component try to match the routes in the parent if I don't use ${match.url} in the route?
I have added a demo for you to easier to understand this problem.
Because when you'll click the /user/:userId: link the app will parse the Router's Switch to see if something matches. If it doesn't it fallback to *.
In your case, you did not specify anything in the Switch to handle /user .
You'll need to move your userId Route declaration to the Switch as they won't share the same first route (/user !== /topics).
<Switch>
<Route path="/" render={Home} />
<Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
<Route path="/user/:userId" render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
<Route render={() => <div>Not Found</div>} />
</Switch>

Reactjs - React Router disallowing paths

I have a route
<Route exact path="/view/:personID" component={PersonView} />
It works fine, however /view still renders, albeit with no person in it. Is there a way to disallow this path or turn in into a 404?
Answer was to use switch
<Switch>
<Route exact path="/view/:personID" component={PersonView} />
<Redirect from='/view' to='/' />
</Switch>
You can manage this on your component, in the render section test if you have your personID if not return a custom error/view.

location.pathname vs router

I am still learning react router v4. and I'd like to know what exactly is the difference between doing this
getting location using
const {
match,
location,
layoutBoxed,
navCollapsed,
navBehind,
fixedHeader,
sidebarWidth,
theme,
} = this.props;
Option 1
if(location.pathname === '/500'){
return <Page500 />
and this
Option 2
<Route path={'/500'} component={Page500} />
As for me, while the first option displays everything properly for me,
the 2nd one i.e. the router one, shows the component in only half the page.
Now, why is that happening?
Option 1 result -->
Option 2 result -->
But the main point--> what is the difference between using location.path name and router
In Option 2 <Route path={'/500'} component={Page500} />
Here you are creating a Route which has a path of /500 and loads a component Page500. This means that when the user navigates to the path specified in the Route, React-Router will render the component where the Route was defined.
In Option 1 ,
if(location.pathname === '/500'){
return <Page500 />
}
the parent component decides when to render the Page500 component, based on the location prop which it receives. This location prop would ultimately be coming from a Route or the withRouter HOC. This is equivalent to
<Route render={(props)=>{
if(props.location.pathname === '/500'){
return <Page500 />;
}else{
return null;
}
}
}
/>
which can also be written as
<Route path={'/500'} component={Page500} />
So to sum it up, you can only do Option 1 if you get the location prop from the parent component, you can define a Route (Option 2) anywhere in the application.
Edit:
If you have all your Routes like
return( <div>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</div> );
you are running the risk of multiple Routes rendering which might be why you are getting half page render in Option 2. To prevent that from happening and only render the first Route that matches, you should add a Switch
return( <div>
<Switch>
<Route path={'/500'} component={Page500} />
<Route path={'/confirm-email'} component={PageConfirmEmail} />
<Route path={'/lock-screen'} component={PageLockScreen} />
<Route path={'/login'} component={PageLogin} />
<Route path={'/sign-up'} component={PageSignUp} />
<Route path={'/forgot-password'} component={PageForgotPassword} />
<Route path={'/fullscreen'} component={PageFullscreen} />
</Switch>
</div> );
More on Switch can be found at https://reacttraining.com/react-router/web/api/Switch
One of the main features with react router is that you can do stuff such as:
<Route path="/user/:id" component={User} />
and id will be passed into User component.
Ex. /user/bob and /user/jill will both render a User component, but in your componentDidMount you can now fetch the correct user information from your API.
With location.pathname that task becomes more convoluted as #palsrealm mentioned. But first of all, the location prop must be available for this method to work.
There are other features that you would be losing out, but that is the main one I can think of so far. You can check out the Route api documentation here.
EDIT: As for why it is rendering differently, I really can't answer without more context. For example, is the Route wrapped in a Switch component like so:
<Switch>
// Other routes
<Route exact path="/500" component={Page500} />
</Switch>

Resources