Ionic React props.match.params doesn't update - reactjs

I'm building a site to display real estate with React and Ionic.
I have this routing in my App.tsx
<IonApp>
<IonReactRouter>
<Nav />
<IonRouterOutlet id="first">
<Route exact path="/" component={Home} />
<Route exact path="/all-properties" component={Properties} />
<Route exact path="/property/:id" component={Property} />
</IonRouterOutlet>
</IonReactRouter>
</IonApp>
And I link to the single "/property/:id" page in my website like this:
<Link to={"/property/" + variableId}> ... </Link>
Now on my "/property/:id" page I can access the id from the URL like this:
useIonViewDidEnter(() => {
console.log(props.match.params.id); // This works the first time
});
The problem is, when I click back to say the home screen, and then visit another of my "/property/:id" pages, the props.match.params.id stays the same. It doesn't update.
What could be done to fix it?

It turned out that it was Ionics lifecycle method that was the problem.
My solution was to make a useEffect instead like this:
useEffect(() => {
console.log(props.match.params.id)
}, [props.match.params.id])

Related

Having issue with defining path for image in a react application

I'm having an issue with defining image path in react application and it's getting frustrating so I'm seeking help from the pros. I'm moving my images folder back and forth between public and src. When background:url(path) works, img src="path" doesn't work and vice-versa. I get this error "Error: Can't resolve 'images/img-2.jpg' in '/Applications/MAMP/htdocs/react-web/src'". If I move the images folder to src, it works but the background:url(path) does not load image. I have the project in https://github.com/miraj977/react-project/. Another issue is github pages; I have setup this project in gh-pages (https://miraj977.github.io/react-project/) but it only loads up to nav and stops. Doesn't load body. Also, I have set homepage in package.json "https://miraj977.github.io/react-project/" but whenever I click the logo which should redirect to homepage, it redirects to "https://miraj977.github.io/". I have shared the link to the github project for you to review the code. It's getting quite frustrating now. Please guide me on the right way to solve these issues. Your time is highly appreciated. Thank you in advance.
Only the navbar showing is actually related to your routing configuration.
Instead of this:
function App() {
return (
<>
<Router>
<Navbar />
<Switch>
<Route path="/" exact component={Home} />
<Route path="/services" exact component={Services} />
<Route path="/products" exact component={Products} />
<Route path="/sign-up" exact component={SignUp} />
</Switch>
</Router>
</>
);
}
do this:
function App() {
return (
<>
<Router>
<Navbar />
<Switch>
<Route path="/react-project" exact component={Home} />
<Route path="/react-project/services" exact component={Services} />
<Route path="/react-project/products" exact component={Products} />
<Route path="/react-project/sign-up" exact component={SignUp} />
</Switch>
</Router>
</>
);
}
Since your homepage url is suffixed with /react-project you want to account for this in your routes and redirects.
So to be extra clear your navigation Link components in your Navbar should also be changed from this:
<Link to="/" className="navbar-logo" onClick={closeMobileMenu}>
1 TRVL 2 <i class="fab fa-typo3" />3{" "}
</Link>
to this:
<Link to="/react-project" className="navbar-logo" onClick={closeMobileMenu}>
1 TRVL 2 <i class="fab fa-typo3" />3{" "}
</Link>
As for the image problem.
For specifying the img by src you can do something like this:
import img1 from "../images/img-1.jpg"; // relative path from directory this component file is in
// ...
<CardItem
src={img1}
text="Explore the hidden waterfall deep inside the Amazon Jungle"
label="Adventure"
path="/services"
/>
For specifying an image as a background image via css you can do something like this:
background: url("../images/img-home.jpg"); // Also relative to current file location
Paths from the public url apparently don't resolve like they used to anymore in create react app 4, see this github issue.

React Router and Links all directing to the same page?

Im pulling my hair out trying to figure out why the list of react Links is all just loading the error page. Could anyone advise please? its almost a direct copy of a previous project that worked perfectly.
Router Set up
function App() {
return (
<Router>
<Switch>
<Route exact path = '/'>
<Home />
</Route>
<Route path = "*">
<Error />
</Route>
<Route path = '/about'>
<About />
</Route>
<Route path = '/contact'>
<Contact />
</Route>
<Route path = '/deckbuilder'>
<DeckBuilder />
</Route>
</Switch>
</Router>
)
}
export default App;
Links on Home Page
export const Home = () => {
return (
<div>
<h1> Home Page </h1>
<Link to = '/contact'>
Contact
</Link>
<Link to = '/about'>
about
</Link>
<Link to = '*'>
Error
</Link>
<Link to = '/deckbuilder'>
Deck
</Link>
</div>
)
}
You should use react router like this and put error component at last, this is correct syntax:
<Switch>
<Route exact path='/' component={Landing} />
<Route exact path='/sign' component={Sign} />
<Route exact path='/login' component={Dashboard} />
<Route component={GenericNotFound} />
</Switch>
I'll add some more information to the #Shivam Jha answer.
worked, strange as this didnt happen on my last project at all
There's no way to work this on previous project if your router configuration is same like above. This issue in not specific to the React router. Even when developing backend applications this can happen.
The thing which make the problem is that start(*) mark. This mark represent any value. By that mean, the second router declartion of your code, i.e route for <Error /> triggered every time when the url is match to *.
That mean,
/abcd
/sign
/login
All of the above paths match to *. So React router does not even check the next router declarations. It simply route to the <Error /> page. So as the solution, you should always declare static routes at the top of the configuration while things like *, :id defined at bottom
Another case is, If you have, two routes as
abcd.com/posts
abcd.com/:id
then If you defined the abcd.com/:id above the abcd.com/poststhen you will never able to send a request to the /posts endpoint. This is not only specific to React router. Even when doing backend development, you have to be aware of this.

React Router in Laravel Blade 404 Not Found Error for deeper url Levels

I am incorporating React in an existing Laravel app.
I created a separate view (documents.blade.php), inside which my root React component is rendered.
In my web.php I created a route that points to this documents view.
Inside my React component I am using React Router.
Although the url for document.blade is working, and my react component is rendering inside it, when I am trying to create sub links with React Router
I am getting a 404 Error, Not Found.
Any ideas on why React Rooter doesn't work?
In my web.php I have tried all the ways bellow:
Route::get('{locale}/documents', function() {
return view('documents');
});
Route::get('{locale}/documents', function() {
return view('documents');
})->where('{locale}/documents', '.*');
Route::view('{locale}/{path?}', 'documents');
In my app.js I have tried:
return (
<Switch>
<Route exact path="/" component={Index} />
<Route path="/create" component={AddDocument} />
<Route path="/edit" component={EditDocument} />
<Route path="/details" component={DocumentDetails} />
</Switch>
);
or
return (
<Switch>
<Route exact path="/" component={Index} />
<Route path={props.locale + "document/create"} component={AddDocument} />
<Route path={props.locale + "document/edit/:id"} component={EditDocument} />
<Route path={props.locale + "document/details/:id"} component={DocumentDetails} />
</Switch>
);
I am accessing the top level url:
http://localhost:8090/public/en/documents (Renders my app component)
,but anything below that is not working like this one:
http://localhost:8090/public/en/documents/create (Does not display my Create component or anything else. I get the 404 error )
Has anyone worked on anything similar?
Thank you in advance.

React-Router - Route re-rendering component on route change

Please read this properly before marking as duplicate, I assure you I've read and tried everything everyone suggests about this issue on stackoverflow and github.
I have a route within my app rendered as below;
<div>
<Header compact={this.state.compact} impersonateUser={this.impersonateUser} users={users} organisations={this.props.organisations} user={user} logOut={this.logout} />
<div className="container">
{user && <Route path="/" component={() => <Routes userRole={user.Role} />} />}
</div>
{this.props.alerts.map((alert) =>
<AlertContainer key={alert.Id} error={alert.Error} messageTitle={alert.Error ? alert.Message : "Alert"} messageBody={alert.Error ? undefined : alert.Message} />)
}
</div>
The route rendering Routes renders a component that switches on the user role and lazy loads the correct routes component based on that role, that routes component renders a switch for the main pages. Simplified this looks like the below.
import * as React from 'react';
import LoadingPage from '../../components/sharedPages/loadingPage/LoadingPage';
import * as Loadable from 'react-loadable';
export interface RoutesProps {
userRole: string;
}
const Routes = ({ userRole }) => {
var RoleRoutesComponent: any = null;
switch (userRole) {
case "Admin":
RoleRoutesComponent = Loadable({
loader: () => import('./systemAdminRoutes/SystemAdminRoutes'),
loading: () => <LoadingPage />
});
break;
default:
break;
}
return (
<div>
<RoleRoutesComponent/>
</div>
);
}
export default Routes;
And then the routes component
const SystemAdminRoutes = () => {
var key = "/";
return (
<Switch>
<Route key={key} exact path="/" component={HomePage} />
<Route key={key} exact path="/home" component={HomePage} />
<Route key={key} path="/second" component={SecondPage} />
<Route key={key} path="/third" component={ThirdPage} />
...
<Route key={key} component={NotFoundPage} />
</Switch>
);
}
export default SystemAdminRoutes;
So the issue is whenever the user navigates from "/" to "/second" etc... app re-renders Routes, meaning the role switch logic is rerun, the user-specific routes are reloaded and re-rendered and state on pages is lost.
Things I've tried;
I've tried this with both react-loadable and React.lazy() and it has the same issue.
I've tried making the routes components classes
Giving all Routes down the tree the same key
Rendering all components down to the switch with path "/" but still the same problem.
Changing Route's component prop to render.
Changing the main app render method to component={Routes} and getting props via redux
There must be something wrong with the way I'm rendering the main routes component in the app component but I'm stumped, can anyone shed some light? Also note this has nothing to do with react-router's switch.
EDIT: I've modified one of my old test project to demonstrate this bug, you can clone the repo from https://github.com/Trackerchum/route-bug-demo - once the repo's cloned just run an npm install in root dir and npm start. I've got it logging to console when the Routes and SystemAdminRoutes are re-rendered/remounted
EDIT: I've opened an issue about this on GitHub, possible bug
Route re-rendering component on every path change, despite path of "/"
Found the reason this is happening straight from a developer (credit Tim Dorr). The route is re-rendering the component every time because it is an anonymous function. This happens twice down the tree, both in App and Routes (within Loadable function), below respectively.
<Route path="/" component={() => <Routes userRole={user.Role} />} />
needs to be
<Routes userRole={user.Role} />
and
loader: () => import('./systemAdminRoutes/SystemAdminRoutes')
Basically my whole approach needs to be rethought
EDIT: I eventually fixed this by using the render method on route:
<Route path="/" render={() => <Routes userRole={user.Role} />} />
Bumped into this problem and solved it like this:
In the component:
import {useParams} from "react-router-dom";
const {userRole: roleFromRoute} = useParams();
const [userRole, setUserRole] = useState(null);
useEffect(()=>{
setUserRole(roleFromRoute);
},[roleFromRoute]}
In the routes:
<Route path="/generic/:userRole" component={myComponent} />
This sets up a generic route with a parameter for the role.
In the component useParams picks up the changed parameter und the useEffect sets a state to trigger the render and whatever busines logic is needed.
},[userRole]);
Just put the "/" in the end and put the other routes above it.
Basically it's matching the first available option, so it matches "/" every time.
<Switch>
<Route key={key} exact path="/home" component={HomePage} />
<Route key={key} path="/second" component={SecondPage} />
<Route key={key} path="/third" component={ThirdPage} />
<Route key={key} exact path="/" component={HomePage} />
<Route key={key} component={NotFoundPage} />
</Switch>
OR
<Switch>
<Route path="/second" component={SecondPage} />
<Route exact path="/" component={HomePage} />
<Route path="*" component={NotFound} />
</Switch>
Reorder like this, it will start working.
Simple :)

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

Resources