Pass id or paramter when redirected ReactJs - javascript

I want to pass id when user clicks on a button and is redirected to another page.
I am using react router, but unable to pass id. So far I tried below code:
<Route path="/editproject/:id" component={EditProject}/>
when user clicks on button :
if (this.state.switchEdit) {
redirect = <Redirect to="/editproject/": {this.state.project.id} />
}
render(){
return (
{ redirect }
)
}
How can I pass id (this.state.project.id)?

You can learn about the Template Literals to concat string.
<Redirect to={`/editproject/${this.state.project.id}`} />
To get the params back you can use that code to retrieve from the params.
this.props.match.params.id
In your case, you are using :id, that's why the code above use .id
<Route path="/editproject/:id" component={EditProject}/>

You can make use of template literals to pass the parameter
if (this.state.switchEdit){
redirect=<Redirect to=`/editproject/:${this.state.project.id}` />
}
render(){
return(
{redirect}
)
}
and Read it from match like this.props.match.params.id in the targetted component

change you code to
if (this.state.switchEdit){
redirect=<Redirect to={`/editproject/:${this.state.project.id`} />
}
render(){
return(
{redirect}
)
}
i made use of template literals
you can access the id through the props of your component
this.props.match.params.id

Related

Using match in react routes

Within my <Switch /> I dynamically create routes with a dynamic path in which ideally will all load the same component.
I have a JSON object like so:
{
"products": [{"name": "car"}]
}
Which just contains an array of products which currently only has one product with the name "car".
In the <Switch /> I loop through the products to create a route like so:
{
ProductHelper.getAllProductPages().forEach(product => {
console.log(product.name);
return (
<Route path={'/' + product.name + '/:id' } component={Search} />
);
})
};
The console log prints out "car" perfectly so i see no issue with getting the product name. However, when I navigate to /car/test I'd expect this to load the Search component but it doesn't.
When I create a route like this:
<Route path='/car/test' component={Search} />
This loads the Search component perfectly to prove that the component doesn't issues.
I really don't understand what im doing wrong here, does anyone have any idea?
Option 1 (recommended)
Use map (no return needed):
{
ProductHelper.getAllProductPages().map(product => <Route path={'/' + product.name + '/:id' } component={Search} />)
};
map builds an array (of components typed Route in this case) and returns it, and that is exactly what you need. When you use forEach it is considering that function as a component to render - and that's wrong.
Option 2 (less recommended)
Alternative way, using forEach instead of map:
A function returns an array of Components:
renderRoutes() {
const productRouters = [];
ProductHelper.getAllProductPages().forEach(product => {
console.log(product.name);
productRouters.push(
<Route path={'/' + product.name + '/:id' } component={Search} />
);
})
return productRouters;
}
And then rendering it:
render() {
return (
<div>
{
this.renderRoutes()
}
</div>
)
}
But I would recommend using map (first option) in that case anyway.
Instead of .forEach you should use .map, because forEach doesn't return an array. Map does

Unable to route to the same component in React

I'm making a simple file navigation UI using React. My route is set like the following:
<Switch>
<Route exact path='/app/file/' component={Files}/>
<Route path='/app/file/:id' component={FilesNav}/>
</Switch>
In both Files and FilesNav components, I have the following piece of code:
<Link to = {`/app/file/${file_id}`}></Link>
Now, when I hit this Link to path from the Files component, it successfully renders the FilesNav component for me. However, since it's a file system and there will be nested folders, I also need to hit the /app/file/:id path from the FilesNav component itself, and this is where it's not working. It updates the query param with the correct id, but it doesn't render the FilesNav component for me again, I'm assuming this is because I'm trying to render a component that I'm already inside of? Can someone please give me an idea how to fix this?
For more context, here's the code for FilesNav:
class FilesNav extends Component{
componentDidMount(){
const { id } = this.props.match.params
this.props.showContents(id)
}
upload = value => {
const { id } = this.props.match.params;
const file = value.file
this.props.uploadFile(file, id)
}
render(){
return(
<div>
<h3>Files</h3>
<div>
<List
bordered
dataSource={this.props.folderContents}
renderItem={item => (<List.Item><Link to = {`/app/file/${item.id}`} key = {item.id}>{item.name}</Link></List.Item>)}
/>
</div>
<span>
<Upload className='upload-button' customRequest={this.upload} showUploadList={false}>
<Button><FontAwesomeIcon icon='upload' />Upload</Button>
</Upload>
</span>
</div>
);
}
}
function mapStateToProps({...}){
return{
...
}
}
export default connect(mapStateToProps ,{ uploadFile, showContents })(FilesNav);
Edit: Added code for FilesNav

Is it an antipattern to set state based on URL?

I have 3 views: stream, playlist, and profile.
Each view requires different buttons (minor differences), but the components do not care about the distinction overall. They continue to retrieve and present data normally.
There is not enough distinction to create different components, i just need a state variable to change the buttons.
Here's the problem: the only way to get the state variable is either a.) in window.location.pathname, or b.) in props passed by react router, which is then made available via the context api. Is one solution better than another? Are they both incorrect for a professional app?
There is nothing wrong with changing your single component depending on what is present in your url. This is a great use case for URL parameters.
Example
function MyComponent(props) {
const { params } = props.match;
const { pathParameter } = params;
if (pathParameter === "home") {
return <div> Welcome to my home page </div>;
} else if (pathParameter === "about") {
return <div> This is the about me page </div>;
} else {
return <div> This is a third option </div>;
}
}
function App() {
return (
<Router>
<div>
<Link to="/home">Home</Link>
<Link to="/about">About</Link>
<Link to="/blog">Blog</Link>
<Switch>
<Route path="/:pathParameter" component={MyComponent} />
</Switch>
</div>
</Router>
);
}

Issue sending value from one class to other in react

Here I have list of values in index.js as
1
2
3
render() {
const { id,heading,body,status,user} = this.props
const {det} = this.state
console.log(val);
return (
<a href='/details' style={{ color: 'green' }} onClick={this.sendValue.bind(this)}>
<div className="member" style={this.style}>
<h1>{id}</h1>
<h3>Reported by: {user}</h3>
<h3>{heading}</h3>
<h5>{body}</h5>
<h5>The current status is: {status}</h5>
</div></a>
)
}
here if I click that div tag mentioned I should be able to render to details page with the id value. I should be able to append the id value with other url mentioned in the details.js
Please help me to find the solution
Your should check this page which uses react-router to implement your scenario.
There can be <Link to="/one">1</Link> for your case and a defined, <Route path="/one" component={One} /> where One is the component which will be rendered when the url is '/one'
You can append the page number in the url after defining in the router as
<Route path="/one/:pageNumber" component={One} />
And in the detailed page component you can read the value using the object
this.props.match.params.pageNumber

React-Router: pass props from one component to another using link

I set up an app with 3 pages, Home, Reptiles and Map.
My problem comes on the Reptiles and Map page. On the reptiles page, I display a list of species, each with a list of range countries and a link "See Map Here". When the user clicks on a country, I want the Map page to be shown with the selected country highlighted (I haven't implemented that yet, so, for now, I just want that country to be passed to the map page).
And when the user clicks on a "See Map Here" for a species, I want the Map page to be shown with all the range countries of that species to be highlighted. Right now I can pass in reptile and country props in the Route for react-router, but when I try to pass in the props in the link directly in the Reptlie.js file, I get the error Warning: Unknown prop reptile on tag.
Remove this prop from the element. Can someone help me figure out how to pass props to links directly in components? Also, how would you generate dynamic URLs? For example, map/species1 or map/country1?
I think my problem is in Reptiles.js. The version of react-router is 3.0.2
Below is my structure:
Below are some images:
Below is my code:
router.js:
const routes = (
<Router history={browserHistory}>
<Route component={App}>
<Route path="/" component={Home}/>
<Route path="reptiles" name="reptiles" component={Reptiles}/>
<Route path="map" name="map" component={Map} country="Taiwan" reptile="Beardy"/>
</Route>
</Router>
);
export default routes;
App.js:
class App extends Component {
render() {
return (
<div className="container">
<header>
<span className="icn-logo"><i className="material-icons">code</i></span>
<ul className="main-nav">
<li><NavLink to="/">Home</NavLink></li>
<li><NavLink to="/reptiles">Reptiles</NavLink></li>
<li><NavLink to="/map">Map</NavLink></li>
</ul>
</header>
{this.props.children}
</div>
);
}
}
export default App;
Reptiles.js:
const Reptiles = () => {
let reptiles = ReptileList.map((reptile) => {
return (
<li className="reptile" key={reptile.id} >
<img className="reptile-img" src={reptile.img_src} />
<h3>{reptile.name}</h3>
<h4> Range
<span className="seeMap">
<NavLink to="map" reptile={reptile.id}>
See Map Here
</NavLink>
</span>
</h4>
{reptile.range.map(function(country,index) {
// only add comma if it's not the last one
return <span key={country}><NavLink to="map" country={country}> {(index < reptile.range.length-1)? country+',' : country} </NavLink></span>
})
}
</li>
);
});
return (
<div className="main-content">
<h2>Reptiles</h2>
<ul className="group">
{reptiles}
</ul>
</div>
);
}
export default Reptiles;
Map.js
var Map = React.createClass({
render: function() {
return (
<div>
<h2>Country passed from props: {this.props.route.country} </h2>
<h2>Reptile passed from props: {this.props.route.reptile} </h2>
</div>
)
}
});
export default Map;
In route.js, you can pass the parameter as follows:
<Route path="map/:countryName/:reptileId" component={Map} name="map" />
In Reptile.jsx,Pass the parameters selected like from props.country or from state wherever you have stored. Make sure to pass some default values in the link when not applicable. For example, for the country in the first link, I have passed all. You can pass according to your requirements. You can pass the parameters as:
<NavLink to={`map/${reptile.id}`}>
<NavLink to={`map/${country}/${reptile.id`}>
and access these parameters through context in Map.jsx this.props.params.reptileId
More about parameters
Like in your case, the parameter reptile id is must in both the cases and country is needed only in the case where specific country is clicked. Hence you can make the parameter country optional and reptile id compulsory. You can follow this
<Route path="map/:reptileId(/:countryName)" component={Map} name="map" />
and then pass accordingly.
<NavLink to={`map/${reptile.id}`}>
<NavLink to={`map/${reptile.id}/${country}`}>
You have three options:
Put the parameters in the URL. This is by far the best default.
e.g. you might have the url /map/beardy, or /map?name=beardy.
You then access these in Map with props.params.whatever or parse props.location.search (e.g. using qs from npm).
Use browserHistory.push's state argument which adds a hidden piece
of data to the history frame. This preserves the ability to refresh the page, or go back and forward in history while preserving the data. The downside is that I can't send a link to someone else and have it load with the selection.
Use redux or similar to store the data in memory. The data will be lost when the page refreshes. This is pretty bad.
To your first question: "how to pass props to links directly in components?". You can't, you do have some workarounds like the ones mentioned in other answers like creating a url that has some data in it and then retrieve it from the url when you load the component. But you can't pass custom props through or .
However, you can pass custom props like you're doing in router.js, except that instead of
This is from your router.js
<Route path="reptiles" name="reptiles" component={Reptiles}/>
You could pass the props like this:
<Route path="/reptiles" render={() => <Reptiles name="reptiles" />} />
To your second question: "how would you generate dynamic urls?"
Suppose you're rendering your component in like this:
class App extends Component {
render() {
return (
<Reptile subtype="foobar" />
)
}
}
Then in Reptile.js you could create dynamic urls like this:
class Reptile extends Component {
render() {
return (
<div>
<NavLink to={`/reptile/${this.props.subtype}`} />
</div>
)
}
}

Resources