Link to not rendering the component again - reactjs

I am using React Link to="" property. I have a url like below.
http://localhost:3000/work/109
After clicking on link, It is successfully going to url like below, But not re-rendering the component again.
http://localhost:3000/work/107
Below is my file, where i am using react-router
import React from 'react';
import { Route, Redirect } from 'react-router-dom';
export const RouteWithSubRoutes = route => (
<React.Fragment>
<Route exact path="/" render={()=>(<Redirect to="/home" />)}/>
<Route exact path={route.path} render={props => (
<route.component {...props} routes={route.routes} onOpenNav={route.onOpenNav}/>
)} />
</React.Fragment>
);
Is there any other property of React, which i am not using.
Note: I am going to same url, But with diffrence id.

you should use 'react-router' params in your Route component path.
also this way new params would send to your component after clicking on Link component.
you could check this.props.match.params to sure it gets update.
then since you want component to re-render you should use getDerivedStateFromProps to get new value and set it to your state.

Related

How to create a route which points to a component in react

I have a table which is as shown below
I have a component which displays the details
How to display the details when click on the first tab of the table
i.e, when clicked on the number 1053 in the first column how to redirect to component with the parameter
Not sure how to build the route localhost:3000/#/sitepage/1053
Is there a way to directly get the route localhost:3000/#/sitepage/1053 so that i can give in the href of the table
Read about https://www.tutorialspoint.com/reactjs/reactjs_router.htm
but not sure how this link to route to write
Please point me to a document which will help me in doing
It you want to redirect to another component, you can use React Router Redirect
This section of React Router documentation will help you, since you haven't posted any code you tried I assumed you're looking for just some documentation to guide you.
Update:
Ok let's assume you have a Router like that:
<Router>
<Route exact path="/" render={(props) => <Table {...props} />}/>
<Route exact path="/column-details/:id" render={(props) => <ColumnDetails {...props} />}/>
</Router>
The props here has a history attribute, so in your <Table> you can have access to it by initializing your component like this
function Table({history}) {
// ...
}
Now in the first column, you need to add an onClick listener, let's say you use <TableCell> that would be
<TableCell onClick={() => history.push(`/column-details/${yourId}`)}/>
Now in your <ColumnDetails> component, we will need access to match attribute to extract our id from the url, so it would be something like:
function ColumnDetails({match}) {
const id = match.params.id;
// ...
}
I hope this is clear enough.
I think you can try react-router-dom to solve your problem, react-router-dom is a wrapper on top of react-router, which brings more flexibility
Let say your table is under Equipments component, then you have to add <Link/> component as alternate to <a> as follows, assuming your equipment object got url and title property
<Link to={`${equimpement.url}`}>{equimpement.title}</Link>
Please note that if you want to use Link component you have to import it on top
import { Link } from "react-router-dom";
And you can manage your routing in your App.js like this way
<div className="content">
<Switch>
<Route path="/not-found" component={NotFount} />
<Route path="/equipments/:id" exact component={EquipmentForm} />
<Route path="/equipments" component={Equipments} />
<Route path="/" exact component={Home} />
<Redirect to="/not-found" />
</Switch>
</div>
Make sure you have imported Route, Redirect and Switch as well in your on top of your App.js
import { Route, Redirect, Switch } from "react-router-dom";
Update
And last if you want to use Route in your app you must wrap your with BrwoserRouter
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
with its import import { BrowserRouter } from "react-router-dom";

Prevent Navigation Component Rendering on Single Route but Render on every other Route

So I have a single Route /reminder, where I do not want my Navigation component, but I want the Navigation component to render on every other Route and I'm not sure how to go about this?
This is my App.js where I am using react-router-dom for my routing.
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Navigation from "./components/navigation/Navigation";
import Reminder from "./components/reminder/Reminder ";
const App = () => {
return (
<>
<Switch>
<Route path="/reminder" component={Reminder} exact />
</Switch>
<Navigation />
<MainContent>
<Router>
<Route path={"/"} component={Dashboard} exact />
</Router>
</MainContent>
</>
);
}
I had a look around for similar issues, but it's mostly for authenticated pages, this isn't for an authenticated page.
I don't want to go down the route of having to add the Navigation component into each of my 21 current routes, it seems like there should a better method?
With my current code above, it renders the Reminder component but still renders the Navigation component.
You can access the match data using a custom hook from react-router. All you need to do is
import { useRouteMatch } from "react-router-dom";
function App() {
let match = useRouteMatch("/reminder");
// Do whatever you want with the match...
return (
<>
<Switch>
<Route path="/reminder" component={Reminder} exact />
</Switch>
{!match && <Navigation />} <---Conditional rendering
<MainContent>
<Router>
<Route path={"/"} component={Dashboard} exact />
</Router>
</MainContent>
</>
);
}
Also, while I didn't change this in your example, it's not generally a good idea to have a route outside of the router component. I'm actually a little surprised react-router-dom didn't throw an error for you.

React router redirect re-rendering the same component it is called from, not redirected to the specified path

I am trying to redirect to a component from another one, after a state change using
in Component B.js, I want a redirect onclick as below:
if(this.state.something) return <Redirect to= "/" />
in Component A.js
`
import { Route,Switch,BrowserRouter as Router} from 'react-router-dom';
const ComponentA = () => {
return (
<Router>
<React.Fragment>
<Switch>
<Route exact path="/somepath/:name/:id/" component={ComponentXYZ} />
<Route path='/' exact component={Log} />
</Switch>
</React.Fragment>
</Router>
)} ;
export default ComponentA ;`
My problem is that the on redirect the URL changes to 'localhost:3000/' but the component A is rendering the route with component 'abc' instead of 'Log'. If I refresh the browser, the Log component renders and displays the view. I tried history.push and also withRouter to solve the issue, but no luck. Kindly help,I'm new to react programming. TIA :)

React Router v4 - Redirect to home on page reload inside application

I need to redirect to home page when user refreshes other pages inside my application. I am using React router v4 and redux. Since the store is lost on reload, the page user reloaded is now empty and hence I want to take him back to a page that does not need any previous stored data. I don't want to retain state in localStorage.
I tried to handle this in event onload but it did not work:
window.onload = function() {
window.location.path = '/aaaa/' + getCurrentConfig();
};
You can try creating a new route component, say RefreshRoute and check for any state data you need. If the data is available then render the component else redirect to home route.
import React from "react";
import { connect } from "react-redux";
import { Route, Redirect } from "react-router-dom";
const RefreshRoute = ({ component: Component, isDataAvailable, ...rest }) => (
<Route
{...rest}
render={props =>
isDataAvailable ? (
<Component {...props} />
) : (
<Redirect
to={{
pathname: "/home"
}}
/>
)
}
/>
);
const mapStateToProps = state => ({
isDataAvailable: state.reducer.isDataAvailable
});
export default connect(mapStateToProps)(RefreshRoute);
Now use this RefreshRoute in your BrowserRouter as like normal Route.
<BrowserRouter>
<Switch>
<Route exact path="/home" component={Home} />
<RefreshRoute exact path="dashboard" component={Dashboard} />
<RefreshRoute exact path="/profile" component={ProfileComponent} />
</Switch>
</BrowserRouter>
It is so amazing that you don't want to keep state of user route map in browser but you use react-router!, the main solution for your case is do not use react-router.
If you don't use it, after each refresh the app come back to main view of app, If you wanna see route map in address bar without any reaction use JavaScript history pushState.
Hope it helps you.

React router: How to update component outside route on param change?

When a url param change, I need to update two components, but one of them is outside the route with the param. The routes in App.js are like this:
<BrowserRouter>
<div>
<Route exact path="/" render={ (props) =>
<Home products={this.state.products} }
/>
<Route path="/products/:product" render={ (props) =>
<Product {...props} /> }
/>
<Route path="/" render={ props =>
<ProductHistory {...props}/> }
/>
</div>
</BrowserRouter>
The ProductHistory which is always visible has links pointing to products, like:
<Link to={`/products/${product.product_id}`}> {product.name}</Link>
When following such a link, the Product component is updated using ComponentWillReceiveProps method:
componentWillReceiveProps(nextProps) {
if(nextProps.match.params.product !== this.props.match.params.product){
But how do I update the ProductHistory component at the same time when the product param change? Since it isn't within the /products/:product route, checking this.props.match.params.product in ProductHistory's componentWillReceiveProps results in undefined.
(edit - and withRouter doesn't help, since it already is within a route, but a different one: "/")
In componentWillReceiveProps I could use location.pathname to check that the path begins with "/product", and I could find the param by substr(path.lastIndexOf('/') + 1.
Edit: But I also have to compare the current id param with the next product id param to avoid unnecessary updates. But when clicking the link, the url have already changed when componentWillReceiveProps fires so location.pathname and nextProps.location.pathname always match, so it updates unnecessarily (repeated api calls).
So I would have to find a different solution - rearrange the routing in some way? The idea is that ProductHistory should always be visible though.
You can render the Route simply like this:
<BrowserRouter>
<div>
<Switch>
<Route exact path="/" render={ (props) =>
<Home products={this.state.products} }
/>
<Route path="/products/:product" render={ (props) =>
<Product {...props} /> }
/>
</Switch>
<ProductHistory />
</div>
</BrowserRouter>
And then in the ProductHistory class you use the withRouter HOC
You can get access to the history object's properties and the closest
Route's match via the withRouter higher-order component. withRouter
will pass updated match, location, and history props to the wrapped
component whenever it renders.
example:
class ProductHistory extends Component { ... }
export default withRouter(ProductHistory);
or using decorators
#withRouter
export default class ProductHistory extends Component { ... }
With this you will be able to access match, location and history through props like this:
this.props.match
this.props.location
this.props.history
For anyone stumbling across this, there is a new solution afforded by hooks, in the form of useRouteMatch in react-router-dom.
You can lay your code out like João Cunha's example, where ProductHistory is not wrapped within a Route. If the ProductHistory is anywhere else but inside the Route for products, all the normal routing information will seemingly give the wrong answer (I think this might have been where the problems with withRouter arose in the replies to João's solution), but that's because it's not aware of the product route path spec. A little differently from most MVC routers, React-router-dom won't be calculating the route that matched up front, it will test the path you're on with every Route path spec and generate the specific route matching info for components under that Route.
So, think of it in this way: within the ProductHistory component, you use useRouteMatch to test whether the route matches a path spec from which you can extract the params you require. E.g.
import { useRouteMatch } from 'react-router-dom';
const ProductHistory = () => {
const { params: { product } } = useRouteMatch("/products/:product");
return <ProductList currentProduct={product || null} />;
};
This would allow you to test and match against multiple URLs that might apply to products, which makes for a very flexible solution!

Resources