Is there a way to view a specific item in an already mapped array in React JS? - javascript

Im in a bit of a bind here and can use some help. Im mapping over an array of items that I got back from an API call, and I render it to the dom as such:
render() {
const newsItems = this.props.news.map((article) => {
return (
<Row>
<Col xs="auto">
<Card
id={article.id}
style={{
height: "40%",
width: "40%",
border: "solid",
margin: "2rem",
}}
>
<CardImg
top
width="100%"
src={article.urlToImage}
alt="Card image cap"
/>
<CardBody>
<CardTitle>
<strong>{article.title}</strong>
</CardTitle>
<CardSubtitle>Athor: {article.author}</CardSubtitle>
<CardText>{article.description}</CardText>
<Button color="primary" size="lg" active>
View Article
</Button>
</CardBody>
</Card>
</Col>
</Row>
);
});
im having difficulty making the view article button work, to view that one particular mapped article in a separate component, I can't seem to pass the information needed. Any help would be appreciated. Also, if it helps, im using redux. Its just that once its mapped, I can't seem to set that button to know what article is clicked to display the information from the array for that particular article.

Related

div height doesn't adjust when Accordion is collapsed

I have two charts on top of each other that extend to the bottom of the screen. The first is collapsible via an Accordion.
However, if I do the following two things in sequence:
Make my browser window bigger
Then, collapse the Accordion (i.e., minimize the first graph).
Then there will be unwanted whitespace below the second graph.
<Flex direction="column" height="calc(100vh)" className="flex-wrapper">
<Box fontSize={["sm", "md", "lg", "xl"]}>Font Size</Box>
<Flex className="flex-wrapper0">
<div>123456789010</div>
<Box className="accordion-box-container">
<Accordion className="accordion-wrapper" allowToggle>
<AccordionItem>
<h2 className="accordion-title">
<AccordionButton
className="accordion-button"
borderRadius="md"
borderWidth="0px"
_focus={{ boxShadow: "none" }}
>
<Box
textAlign="left"
h={3}
_focus={{ boxShadow: "none" }}
></Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel p="0">
<Box height="30vh">
<ThreeDataPoint />
</Box>
</AccordionPanel>
</AccordionItem>
</Accordion>
<div className="graph-wrapper">
<ThreeDataPoint />
</div>
</Box>
</Flex>
</Flex>
It seems like some interaction problem between browser resizing and css? I think I need to force a re-rendering of <ThreeDataPoint /> whenever the accordion button is pressed so that it can pick up the new height that it's supposed to be using. I wonder how to force such a re-rendering?
Here's codesandbox:
https://codesandbox.io/s/elegant-fermat-bugv1?file=/src/index.tsx
And the app URL:
https://bugv1.csb.app/
It was because of this !important flag causing troubles in the css file:
.graph-wrapper div {
height: 100% !important;
}
After commenting this out, it worked as expected.

Why doesn't Next.js Json.map work properly?

I want to build a simple component where the data comes from a JSON list. On the website I can see the console.log(dat.CardId) so it works for just console.log(). I can't see the cards from the .map function. The Style is bootstrap. I really don't think that something is wrong at the code.
import { Card,Button,Container,Row,Col } from 'react-bootstrap'
const data = [{'CardTitle':'Simple Website','CardText':"Some quick example text to build on the card title and make up the bulk of the card's content.", "CardId":"Simple-Website"},{'CardTitle':'Simple Website','CardText':"Some quick example text to build on the card title and make up the bulk of the card's content.", "CardId":"Simple-Website"} ]
export default function Cards() {
return (
<>
<div>
<Container fluid>
Cards
{data.map(dat => {
{console.log(dat.CardId)}
<Row>
<Col>
<Card style={{ width: '18rem' }}>
<Card.Img variant="top" src="pexels-tima-miroshnichenko-6612358 (2).jpg/100px180" />
<Card.Body>
<Card.Title>{dat.CardTitle}</Card.Title>
<Card.Text>
{dat.CardText}
</Card.Text>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
</Col>
</Row>
})}
</Container>
</div>
</>
)
}
Use return ( ... ) in a .map to render an element. https://stackoverflow.com/a/39999745/15257712
Example:
array.map((entry, index) => {
return (
<div key={index}>
...
</div>
)
})

Rendering each value from a firebase array into <li> with ReactJS

I'm working on a recipe app and I'm having some issues rendering my ingredient list from a Firebase array. I'm new to JS and React, so i apologize if this is something simple. I really appreciate any help that's provided! I've attached my code and an example of how the array is currently being rendered. I've also included a screenshot of the Firebase data structure. [firebaseStructure][1]
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCard(snapshot.docs.map(doc => ({id:doc.id, recipes:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id, recipes:doc.data()})))
})
}, []);
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot =>{
setIngredientsList(snapshot.docs.map(doc =>({id:doc.id, ingredient: doc.data().ingredients1})));
console.log(snapshot.docs.map(doc =>({id:doc.id, ingredient: doc.data().ingredients1})))
})
}, []);
return (
<div>
<Container>
<Row>
{recipeCard.map(recipes =>(
<Col md={4} key={recipes.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipes.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipes.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipes.id}>
{ingredientsList.map(recipes =>(
<li key={recipes.id}>
{recipes.ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
)
}
[current rendered output][2]
[1]: https://i.stack.imgur.com/bFBdr.png
[2]: https://i.stack.imgur.com/xU1fC.png
I think a lot of the confusion here has come from the naming convention, and the attempt to use separate state for the recipieCard and ingredientsList. You've ended up rendering all the ingredients for all recipies instead of just the one's relevant to that recipie. If you ever find yourself accessing properties like recipies.recipies, you know you need to do some refactoring (if you have complete control of the project).
First things first, you only need one useEffect to access your database and process the data. It all belongs together, so there's no need to separate it into separate states. Notice how I've renamed the state as recipieCards plural. This is an array or list of data objects, so it should have a pluralised name. Each data object now has the property data instead of recipies, which more accurately describes what it contains (i.e. the data for ONE recipie).
useEffect(() =>{
database.collection('recipes').onSnapshot(snapshot => {
setRecipeCards(snapshot.docs.map(doc => ({id:doc.id, data:doc.data()})));
console.log(snapshot.docs.map(doc => ({id:doc.id, data:doc.data()})))
})
}, []);
Now in the return fuction it becomes much more clear what's going on. We take the array of recipieCards and map over it to access each recipie data object one at a time. For each data object use the id as its key, and take the url and title from data. Now you can access that recipie's ingredients directly from the same data object, under the property data.ingredients1.
return (
<div>
<Container>
<Row>
{recipeCards.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.data.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.data.title}</Card.Title>
{/**<Card.Text> **/}
<ul>
{recipie.data.ingredients1.map(ingredient =>(
<li key={ingredient}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
</Row>
</Container>
</div>
);
You don't need to call the DB twice in two separate useEffect to do what you want. You should only call the DB once for efficiency in this case.
Also, you're re declaring recipes within the second map, this could cause errors, you should avoid using the same variable name for different variables. Your problem may be related to this. I edited the following code assuming you only use the first useEffect with setRecipeCard.
{recipeCard.map(recipe =>(
<Col md={4} key={recipe.id}>
<Card style={{ width: '100%' }}>
<Card.Img variant="top" src={recipe.recipes.url} style={{height:'300px',width:'100%'}} />
<Card.Body>
<Card.Title>{recipe.recipes.title}</Card.Title>
{/**<Card.Text> **/}
<ul key={recipe.id}>
{recipe.ingredients1.map(ingredient =>(
<li key={recipes.id}>
{ingredient}
</li>
))}
</ul>
{/** </Card.Text> **/}
<Button variant="secondary">Head to Recipe</Button>
</Card.Body>
</Card>
</Col>
))}
Can you try out this code? Please let us know specifically if you are getting any errors :)

Is there a way to map over an array of objects in react and also get the accosiated images from cloudinary

I am trying to map over an array of objects in react, the object includes a product name and id. Im using cloudinary to store my images but im not sure what to put as the publicId
Im trying to get the public id associated with each object to pass into the public id
This is my code
<div>
<Container>
<h2>My Products</h2>
<CardDeck>
{myProducts.map((product) => (
<Card style={{ minWidth: "14rem" }}>
<Image cloudName='dgeizgzdw' publicId="equipped/{product._id}" className='card-img-top'/>
<Card.Body>
<Card.Title>{product.product}</Card.Title>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
))}
</CardDeck>
</Container>
</div>
It works when i hard code the product id like so.
<div>
<Container>
<h2>My Products</h2>
<CardDeck>
{myProducts.map((product) => (
<Card style={{ minWidth: "14rem" }}>
<Image cloudName='dgeizgzdw' publicId={'equipped/5f1fcbd42371c61758db2962'} className='card-img-top'/>
<Card.Body>
<Card.Title>{product.product}</Card.Title>
<Button variant="primary">Go somewhere</Button>
</Card.Body>
</Card>
))}
</CardDeck>
</Container>
</div>
);
Ive tried interpolating the public id the main issue is that the first part of the string 'equipped/ is not saved in the public id
Instead of:
<Image cloudName='dgeizgzdw' publicId="equipped/{product._id}" className='card-img-top'/>
write:
<Image cloudName='dgeizgzdw' publicId={`equipped/${product._id}`} className='card-img-top'/>

How to Update content using ReactJS

I'm new in React and I trying to build a simple list of items clickable to get data and update the DOM, I have a list of links on render()
const listNews = this.state.news.map((item, i) =>
<ListGroupItem key={i} className="font-size-1 text-left">
<a href='#' onClick={() => this.getInfoNews(i)}>{item.title}</a>
</ListGroupItem>
);
the function "getInfoNews(i)" have this piece of code to display the data into DOM
getInfoNews(i){
var content = {
news : this.state.news[i]
}
console.log(content.news)
if(content.news === undefined){
return (
<Card>
<CardBody>
<CardTitle>Card Title</CardTitle>
<CardSubtitle>Card subtitle</CardSubtitle>
<CardText>Some quick example text to build on the card title and card's content.</CardText>
</CardBody>
</Card>
)
}else{
return (
<Card>
<CardBody>
<div className="container">
<img src={content.news.urlToImage} className="w-100" />
<CardTitle>
<div className="bottom-left font-size-2 bg-dark w-50 p-2 text-uppercase text-left">{content.news.title}</div>
</CardTitle>
</div>
<CardSubtitle className="text-right text-dark font-size-1 mr-4">
by {content.news.author ? content.news.author : "Anonymous"} , published at {content.news.publishedAt}
</CardSubtitle>
<CardText className="text-dark font-size-2 mt-4">
{content.news.description} read more
</CardText>
</CardBody>
</Card>
)
}
}
Work perfect on load first time, but dont work once clicked on every link, the data is loaded but the DOM dont update, some one can help me ? thanks!
React re-renders whenever there is an update to either the state or the props.
For example, you can load new data from API, and then do this.setState to update the component state. Then, react will re-render the component automatically.

Categories