problem rendering items with props.match.params.id - reactjs

I am trying to implement a simple query string matches to show the appropriate item.
here is the component which will render further info on a listed item:
const Product = (props) => {
console.log(props.match.params.id)
console.log(data.products)
const product = data.products.find((x) => x.id === props.match.params.id);
if (!product) {
return <div>product not found!</div>;
}
while both of thoese consule logs give me what i want the product does not seem to be found. here is my product list:
const data={
products:[
{
id:1,
brand:'Nappies',
price:1200
},
{
id:2,
brand:'Knitted Goods',
price:1400
},
{
id:3,
brand:'Baked Treats',
price:1100
},
{
id:4,
brand:'Clothes',
price:1100
}
]
}
and i am matching the querys with this ...
<Link to={`/product/${product.id}`}><button className="card bg-gray-700 hover:bg-red-600 transition text-white w-full h-1/6 absolute bottom-0">See More</button></Link>
the above button is the button a user clicks to see more on that item (price, name, stock, etc)
when clicking that link it takes me to the appropriate page url. (http://localhost:3000/product/2 )but its giving me the "no item found visually on the page"
this is how my app.js is set up... fairly simply:
<Nav />
<Switch>
<Route exact path='/'>
<Homepage />
</Route>
<Route path='/product/:id' component={Product}/>
</Switch>
</Router>
it seems to be like the find method isn't working? such a bizarre problem. am i missing something really obvious? been coding about a year and still find myself stumped on simple react stuff lately :/ so discouraging.
its not rendering any of my info after that in the individial product component
shown down below:
<li>
<div className="row">
<div>{product.name}</div>
<div className="price">{product.price}</div>
</div>
</li>
essentially i want the above code rendered after clicking one of the listed items. its saying "cannot get id of undefined".... seems to be something with me find method but even then i still can't figure out what could be wrong?!?

propps.match.params.id seems to be a string
but, when your looks for a particular product, you use strict match
const product = data.products.find((x) => x.id === props.match.params.id);
your id is number, '2' === 2 is false
So, try
const product = data.products.find((x) => x.id === Number(props.match.params.id));

Do use useParams hook to retrieve id as
const Product = (props) => {
let { id } = useParams();
return (
<div>
<h3>ID: {id}</h3>
</div>
);
}
For further details check here https://reactrouter.com/web/example/url-params

Related

How to route a details page of a photo when clicked in React?

I have a react component which returns some photos that i got from an API. What i want is, when i click to a particular photo, i want to go to a details page ,and not see the other photos around the clicked one.for each different photo, i want to go to the url '/photoId' and i want that url doesn't include anything except the details page. think it like amazon shopping. in the browsing page you see a lot of different products,but when you click them, you go to a details page and don't see other products anymore. you see price, reviews etc in that detail page. that is what i want to do.
here is the code that i use for routing right now. characters is an array that i fetched from api.
And Detail is the component that takes a character prop and returns details about it.
Currently , when i clicked a photo, i see the details but i see other products too. How to fix it?
in the normal flow of the page , page looks like this right now:normal flow
but when i click to a button, it looks like this:clicked
Thanks for help.
<ul>
{characters.map(x =>
<li>
<Link to={`/${x.id}`} >
<div className='profile'>
<img className='profileImage' src={x.image} />
<div className='profileName'></div>{x.name}
</div>
</Link>
<Route exact path={`/${x.id}`} component={() => <Detail character={x} />} >
</Route>
</li>)}
</ul>
Here's a working snippet that mimics your additional code sample - the Switch shouldn't actually be necessary but it doesn't work properly without it in Stack Snippets for some reason.
I also added in some basic state and paramater validation to demonstrate how to control routing when you can't pass the character data directly from the link, like your were trying to do in your original example.
I'd recommend looking over any unfamiliar aspects of the api at the react router docs.
const { useState } = React;
const { BrowserRouter, Route, Link, Redirect, Switch } = window.ReactRouterDOM;
const Detail = ({ name }) => {
return <h2>{name}</h2>;
};
const App = () => {
const [characters] = useState([
{ name: "rick" }, { name: "morty" }
]);
return (
<BrowserRouter>
<Switch>
<Route exact path="/">
<Link to="/rick">go to rick</Link>
<Link to="/morty">go to morty</Link>
<Link to="/summer">go to summer</Link>
</Route>
<Route exact path="/:id" render={(routeProps) => {
const id = routeProps.match.params.id;
const exists = characters.find((char) => char.name === id);
if (exists) return <Detail name={exists.name} />;
return <Redirect to="/" />;
}}
/>
</Switch>
</BrowserRouter>
);
};
ReactDOM.render(<App />, document.body)
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-router-dom/5.0.1/react-router-dom.min.js"></script>

Disqus email notifications open localhost instead of the real website

I am using Gastbyjs with Disqus plugin for commenting function. I followed the instruction here
I received emails about comments in my blog, but when I clicked the button "Reply to XXX" it opens.
https://localhost:8000/blogs/article-name
I think I missed some configuration for this.
Update 1
Here is the code where I use the config:
export const BlogPostTemplate = ({
content,
contentComponent,
description,
tags,
title,
helmet,
}) => {
const PostContent = contentComponent || Content;
const disqusConfig = {
shortname: process.env.GATSBY_DISQUS_NAME,
config: { identifier: title },
};
Update 2
I managed to use Reach/Router to access Location
I installed reach/router and I updated my code:
import { Location } from "#reach/router";
export const BlogPostTemplate = ({
content,
contentComponent,
description,
tags,
title,
helmet,
location
}) => {
const PostContent = contentComponent || Content;
console.log('--------------location---------');
console.log(location);
const disqusConfig = {
url: location.href,
shortname: process.env.GATSBY_DISQUS_NAME,
config: { identifier: title },
};
return (
<section className="section">
{helmet || ""}
<div className="container content">
<div className="columns">
<div className="column is-10 is-offset-1">
<h1 className="title is-size-2 has-text-weight-bold is-bold-light">
{title}
</h1>
<p>{description}Cool</p>
<PostContent content={content} />
{tags && tags.length ? (
<div style={{ marginTop: `4rem` }}>
<h4>Tags</h4>
<ul className="taglist">
{tags.map((tag) => (
<li key={tag + `tag`}>
<Link to={`/tags/${kebabCase(tag)}/`}>{tag}</Link>
</li>
))}
</ul>
</div>
) : null}
<DiscussionEmbed {...disqusConfig} />
</div>
</div>
</div>
</section>
);
};
const BlogPost = ({ data }) => {
const { markdownRemark: post } = data;
return (
<Layout>
<Location>
{({ location }) => (
<BlogPostTemplate
content={post.html}
contentComponent={HTMLContent}
description={post.frontmatter.description}
helmet={
<Helmet titleTemplate="%s | Blog">
<title>{`${post.frontmatter.title}`}</title>
<meta
name="description"
content={`${post.frontmatter.description}`}
/>
</Helmet>
}
tags={post.frontmatter.tags}
title={post.frontmatter.title}
location={location}
/>
)}
</Location>
</Layout>
);
};
However, when someone left a comment and I click the "Reply to {somebody}" button in the notification email, it still opens the localhost, rather than the real website link.
I finally figured it out. I'd like to break the answer into 4 parts:
How does the localhost url sneak into the comment's url?
The localhost url sneaked into the comment's url when I was commenting my article in a localhost development environment.
So to prevent this from happening again, only posting a comment in the production environment. If you did it in localhost environment, how to fix it? Please look at point 3.
What does localhost url is called?
The comment url is called Discussion Url.
Why do we need to know it?
Because this will be the key words for searching any related questions/answers. Without knowing this, I have wasted days for searching this configuration in Disqus.
So in short, it saves you tremendous time.
How and where to solve it?
As you can see there, the 2nd blog Link was using localhost, after I updated to the real website url, the problem was solved.
Hope my answer is helpful.
You need to pass the url to the disqusConfig of the current page disqus is located. In Gatsby, you can expect the location prop to be available to you on every page thanks to its use of #reach/router.
In your component:
import {Disqus} from "gatsby-plugin-disqus";
const Article = (props) => {
let disqusConfig = {
url: props.location.href,
identifier: props.your.identifier.source,
title: props.your.title.source,
};
return (
<div className="article">
<h1>Article title</h1>
<div>Article text</div>
<Disqus config={disqusConfig} />
</div>
)
}
Plugin config:
{
resolve: `gatsby-plugin-disqus`,
options: {
shortname: `your-short-name`
}
}
Note: you can't use something like window.location because there is no window during build time (there is no browser server side).

How to use a variable (a URL saved as a string) from another component?

Question: How can I use different URLs from different components in a third component as one ?
I am learning React.js and I would like to make multiple pages. This is an example project for learning purposes. There is one page where I can see the images and info of TeamA and there is another page where I can see the images and info of TeamB.
In order to avoid duplicates, I want to separate small components. I have a Card component which displays the image of team members with name and info. I want to use this one Card component for the page TeamA and also for the page TeamB.
The only difference now is the URL for the images - there is 1 URL for TeamA and one for TeamB. It should change accordingly.
I hope I could describe the problem. Please see the code examples below.
I appreciate your help. Have a nice day!
1st Component which has a unique URL for images:
const TeamA = ({id}) => {
const exampleImages = `https://url`;
return (
<div>
<Teams>
<Card teamImg={exampleImages}/>
</Teams>
</div>
);
}
2nd Component which also has a unique URL for images:
const TeamB = ({id}) => {
const exampleImagesB = `https://url`;
return (
<div>
<Teams>
<Card teamImg={exampleImagesB}/>
</Teams>
</div>
);
}
The Component that displays the information of the Team component (above). In this component, I want to use the URLs from the other components and add it to the img tag.
const Card = ({ name, email, id, teamImg }) => {
return (
<div className='tc'>
<img alt='image' src={`${teamImg}`}/>
<div>
<h2>{name}</h2>
<p>{info}</p>
</div>
</div>
);
}
You can make team a functional component of it's own:
const Team = ({id, imageUrl}) => {
return (
<div>
<Teams>
<Card teamImg={imageUrl}/>
</Teams>
</div>
);
}
Then you can pass imageUrl into your teams at a higher level without writing them out as separate components each time.
For example if you have your different urls as an array, this could be the component above team:
const AllTeams = () => {
const images = [{ id: 1, url: 'url1' }, { id: 2, url: 'url2' }];
return (
<>
{ images.map(image => <Team key={image.id} imageUrl={image.url} />) }
</>
);
}

How can I redirect the page when I click on an suggestive item from React Semantic UI Search Module?

I am trying to create a search bar built on the top of Semantic UI React like this:
resource: standard search
I am currently using create-react-app with Link and Switch from react-router-dom. I have already tried similar solutions with history.push, but didn't redirect the page with my list. I could not found any example on how to redirect the page after I click on an item and outputs a div with a list in the new page containing some objects from Search result.
Here are some templates of my files structure:
###App.js###
export default function App() {
return (
<React.Fragment>
<Navbar />
<Switch>
<Route exact path="/" component={ProductList} />
<Route path ="/details" component={Details} />
<Route path="/cart" component={Cart} />
<Route path="/form" component={Form} />
<Route component={Default} />
</Switch>
...
</React.Fragment>
);
}
I need to redirect to /details page after I click on the suggestive item.
###SearchForItem.js###
class SearchForItem extends Component {
componentWillMount() {
this.resetComponent()
}
goToDetailsPageDiv(e, result) {
{console.log(result)}
return (
<Link to="/details">
<ui>
<li>{result.title}</li>
<li>{result.description}</li>
<li>{result.image}</li>
</ui>
</Link>
);
}
resetComponent = () => this.setState({ isLoading: false, results: [], value: '' })
handleResultSelect = (e, { result }) => this.goToDetailsPageDiv(e, result);
handleSearchChange = (e, { value }) => {
this.setState({ isLoading: true, value })
setTimeout(() => {
if (this.state.value.length < 1) return this.resetComponent()
const re = new RegExp(_.escapeRegExp(this.state.value), 'i')
const isMatch = result => re.test(result.title)
this.setState({
isLoading: false,
results: _.filter(source, isMatch),
})
}, 300)
}
render() {
const { isLoading, value, results } = this.state
return (
<Search
onResultSelect={this.handleResultSelect}
onSearchChange={_.debounce(this.handleSearchChange, 500, { leading: true })}
loading={isLoading}
results={results}
value={value}
//
input={{placeholder: "Search..."}}
noResultsMessage={"Nothing found"}
{...this.props}
/>
)
}
}
onResultSelect is supposed to handle the data after I click on these items.
The console.log outputs correctly all the object's properties after I clicked on the target item:
{
description: "description-template"
image: "img/products/product-template"
title: "title-template"
}
But the issue I am trying to solve is to redirect these properties to the page /details inside a div with a list with these 3 properties similar to what I tried to produce here:
goToDetailsPageDiv(e, result) {
{console.log(result)}
return (
<Link to="/details">
<ui>
<li>{result.title}</li>
<li>{result.description}</li>
<li>{result.image}</li>
</ui>
</Link>
);
}
Can someone please shed light on how can I redirect the page correctly?
Currently working on this right now as well, the only way I have come up with doing it (not without its flaws) is using this.props.history.push("{LINK TO REDIRECT HERE}") in the handleResultSelect arrow function. Will probably come back and update this answer after I have hashed out the issues but I believe this is the best way to do it.

react router redux url

I am making my first web-app using react, react router v4, and redux/react-router-redux.
it is a shopping site. I have my list of my products saved in the store and can access them fine. I have produced a products list page, when clicking on the products' image i have routing setup to take me to a new url(/'productmodel').
Currently I have a 'ProductPage' component for which I have passed in props relevant to the specific product, for each corresponding route, within my router. This seems like a very long way of doing things.
What I would like to do is render for each of the routes and then have the ProductPage component itself, render the right product depending on the route (URL address).
What is the best way to do this??
Thank you in advance :)
Are you after something like this?
ProductsListPage:
....
render() {
<div>
{this.props.products.map(product =>
<Link key={product.id} to={"/product/"+product.id}>
{product.name}
</Link>
)}
</div>
}
....
ProductPage:
....
componentWillMount() {
this.props.actions.getProduct(this.props.match.params.productid);
}
....
render() {
<div>
<span>{this.props.product.name}</Link>
</div>
}
....
Your route for product page would look like this:
<Route exact path="product/:productid" component={ProductPage} />
So what's happening here is when you click on a product on Products List page, you get redirected to the product page that has the product id as a parameter. On component mount on product page, you retrieve the product passing the productid from params (url).
ok so I manage to do it!
I created a ProductPageContainer inorder to pass my products list from the store:
function mapStateToProps(state) {
let products = state.kitsProducts;
return {
products: products
};
};
I then, within my component, got the productid from the params; as suggested by Hossein:
createProductPageComponent() {
let activeProduct = this.props.products.filter(product => product.id === this.props.match.params.productid)
return activeProduct.map(product =>{
return (
<ProductPage
key={product.id}
brand={product.brand}
productName={product.model.toUpperCase()}
price={"£"+product.price}
productImage={product.image}
text={product.text}
/>
)
})
}
and now my product page renders to the the right route, depending on which product was selected in the previous product list page. And the right product, depending on what route it has been rendered in.
Thanks Hossein!!! You helped me more than you may think!

Resources