React won't render within map function - javascript

I'm trying to render an array containing some objects using the JS function map().
However when I return the text nothing is shown:
console.log(this.props.project.projects); // (2) [{…}, {…}]
this.props.project.projects.map((item, index) => {
console.log(item.projectDescription); //"Testproject"
return (
<div key={index}>
{item.projectDescription}
</div>
)
})
I just don't get it, why there is no text shown, since the console.log(item.projectDescription) shows exactly what I want to display.
Update:
It works when I change it to this:
return this.props.project.projects.map((item, index) => (
<div key={index} style={{ color: '#fff' }}>
{item.projektBeschreibung}
</div>
))
I already thought about using the foreach-method but I think it should actually work using the map()-function.
Here you can see also the render method of my Component.
class ProjectRow extends Component {
renderProjects() {
console.log(this.props.project);
if (this.props.project.loading) {
return (
<div style={{color: '#fff'}}>
Loading
</div>
)
} else {
console.log(this.props.project.projects);
this.props.project.projects.map((item, index) => {
console.log(item);
console.log(item.projektBeschreibung);
console.log(index);
return (
<div key={index}>
{item.projektBeschreibung}
</div>
)
})
}
}
render() {
return (
<div>
{this.renderProjects()}
</div>
);
}
}

The renderProjects function is not returning anything when it hits your else case. Here is an example of use:
renderProjects() {
console.log(this.props.project);
if (this.props.project.loading) {
return (
<div style={{color: '#fff'}}>
Loading
</div>
)
} else {
console.log(this.props.project.projects);
// added return statement here
return this.props.project.projects.map((item, index) => {
console.log(item);
console.log(item.projektBeschreibung);
console.log(index);
return (
<div key={index}>
{item.projektBeschreibung}
</div>
)
})
}
}

why not use map like below ?
render(){
return(
<div>
{this.props.project.projects.map((item, index) => (
<div key={index}>
{item.projectDescription}
</div>
))}
</div>
)
}

Related

Redirect to description page from Card component in Reactjs

Appreciate your kind help!
What I'm trying to achieve is that on click of cardlist component it has to open respective product detail page just like e-commerce website.
I have created :
CardList component, card component, data(where it contain array of
object) and singleCardComponent(i.e the description page component)
I think I had made a mistake in cardList component.
I have got stuck on the logic how i will redirect to respective product page.
//--------------------card component--------------------
class Card extends Component {
render() {
return (
<div className='col-md-3 col-10 mx-auto mb-4'>
<div className="card">
<img src={this.props.imgsrc} className="card-img-top" alt="..." />
<div className="card-body">
<h5 className="card-title">Rs {this.props.price}</h5>
<p className="card-text">{this.props.title}</p>
<p className='card-date d-flex justify-content-end'>Oct 29</p>
</div>
</div>
</div>
)
}
}
//--------------------cardlist component--------------------
class CardList extends Component {
show_component = (i) => {
Data.map((v) => {
return <SingleCardComp
key={i}
imgsrc={v.imgsrc}
price={v.price}
title={v.title}
seller={v.seller_desc}
desc={v.description}
loc={v.location}
/>
})
}
render() {
return (
<div className='row'>
{
Data.map((val, i) => {
return <button onClick={()=>this.show_component(i)}>
<Card
key={i}
imgsrc={val.imgsrc}
price={val.price}
title={val.title}
/>
</button>
})
}
</div>
)
}
}
//--------------------Data--------------------
const Data = [
{
imgsrc: image0,
title: "Samsung A50",
price: 35500,
seller_desc: 'Bilal',
description: "Lorem, ipsum dolor sit",
location:'Kansas'
}
];
//--------------------SingleCardComp--------------------
class SingleCardComp extends Component {
render() {
return (
<div>
<img src={this.props.imgsrc} alt="..." />
<h5>Rs {this.props.price}</h5>
<p >{this.props.title}</p>
<h1>
Description:{this.props.desc}
</h1>
<h1>
Seller Details:{this.props.seller}
</h1>
<h1>
Posted in:{this.props.loc}
</h1>
</div>
)
}
}
Here is the image of card
The show_component method seems the problem here,
What is the Data means in the show_component method? Is that the same array used in CardList->render method? If that is the case what you need to do is update your show_component method like this,
show_component = (i) => {
Data.map((v, index) => {
if(index === i) {
return <SingleCardComp
key={i}
imgsrc={v.imgsrc}
price={v.price}
title={v.title}
seller={v.seller_desc}
desc={v.description}
loc={v.location}
/>
}
})
}
This is the solution with minimum change. However, the better solution would be to pass the card data in the show_component method as parameter. Like this,
state = {
selectedItem: null,
showSingleCardComp: false,
selectedItemIndex: 0,
}
show_component = (v, i) => {
this.setState({selectedItem: v, showSingleCardComp: true, selectedItemIndex: i});
}
And call the show_component method like this,
render() {
return (
<div className='row'>
{
Data.map((val, i) => {
return <button onClick={()=>this.show_component(val, i)}>
<Card
key={i}
imgsrc={val.imgsrc}
price={val.price}
title={val.title}
/>
</button>
})
}
{this.state.showSingleCardComp && (
<SingleCardComp
key={this.state.selectedItemIndex}
imgsrc={this.state.selectedItem.imgsrc}
price={this.state.selectedItem.price}
title={this.state.selectedItem.title}
seller={this.state.selectedItem.seller_desc}
desc={this.state.selectedItem.description}
loc={this.state.selectedItem.location}
/>
)}
</div>
)
}

Pass Props to parent componenet in React

I'm trying to pass id from child component(and nested component) to it's parent.
var Comment = React.createClass({
handleClick: function(id){
console.log(this.props, id)
this.props.handleClick(this.props.comment.id)
},
render: function() {
var comment = this.props.comment
return <div className="Comment">
<div onClick={()=> this.handleClick(comment.id)} dangerouslySetInnerHTML={{__html: comment.comment_text}}/>
{comment.children.length > 0 && comment.children.map(function(child) {
return <Comment key={child.id} comment={child}/>
})}
</div>
}
})
but the function in child it's undefined and also not to make function availble in nested child.
https://jsfiddle.net/yk5nomzb/1/
Any help would be appreciate it
I made it work by changing the function into an arrow function inside the App.js render like this:
render() {
return (
<div>
{this.props.comments.map(comment => {
return (
<Comment key={comment.id}
handleClick={this.handleClick}
comment={comment}
/>
);
})}
</div>
);
}
Also in the Comment component, you need to add handleClick prop to the child Comment components like this:
render() {
var comment = this.props.comment;
return (
<div className="Comment">
<div
onClick={() => this.handleClick(comment.id)}
dangerouslySetInnerHTML={{ __html: comment.comment_text }}
/>
{comment.children.length > 0 &&
comment.children.map(child => {
return (
<Comment
key={child.id}
handleClick={this.props.handleClick}
comment={child}
/>
);
})}
</div>
);
}
So the problem is likely the famous this and bind issue in javascript.
Codesandbox

Pass index as state to component using React

I have 4 different divs each containing their own button. When clicking on a button the div calls a function and currently sets the state to show a modal. Problem I am running into is passing in the index of the button clicked.
In the code below I need to be able to say "image0" or "image1" depending on the index of the button I am clicking
JS:
handleSort(value) {
console.log(value);
this.setState(prevState => ({ childVisible: !prevState.childVisible }));
}
const Features = Array(4).fill("").map((a, p) => {
return (
<button key={ p } onClick={ () => this.handleSort(p) }></button>
)
});
{ posts.map(({ node: post }) => (
this.state.childVisible ? <Modal key={ post.id } data={ post.frontmatter.main.image1.image } /> : null
))
}
I would suggest:
saving the button index into state and then
using a dynamic key (e.g. object['dynamic' + 'key']) to pick the correct key out of post.frontmatter.main.image1.image
-
class TheButtons extends React.Component {
handleSort(value) {
this.setState({selectedIndex: value, /* add your other state here too! */});
}
render() {
return (
<div className="root">
<div className="buttons">
Array(4).fill("").map((_, i) => <button key={i} onClick={() => handleSort(i)} />)
</div>
<div>
posts.map(({ node: post }) => (this.state.childVisible
? <Modal
key={ post.id }
data={ post.frontmatter.main.[`image${this.state.selectedIndex}`].image }
/>
: null
))
</div>
</div>
);
}
}
This is a good answer which explains "Dynamically access object property using variable": https://stackoverflow.com/a/4244912/5776910

Rendering multiple states one after the other using .map

I'm having some difficulty with rendering using .map. What I'm trying to do is to render the artist name, the song title, and a link to a page where you can find sheet music. I have a separate state for each one of these categories and it looks like this:
this.state = {
currentSearch: "",
artistName: [],
songTitle: [],
tabId: [],
}
Here is my render:
render(){
return(
<div>
{this.props.artist.map((artist, i) =>{
return(
<h3>{artist}</h3>
)
})}
{this.props.title.map((title, i) => {
return (
<h3>{title}</h3>
)
})}
{this.props.link.map((link, i) => {
return (
<h3>{link}</h3>
)
})}
</div>
)
}
The main problem that I'm having is that the information will display on the page like this:
The Beatles
The Beatles
The Beatles
All You Need Is Love
Blackbird
Twist and Shout
www.allyouneedisloveurl.com
www.blackbirdurl.com
www.twistandshouturl.com
Is there a way I can map these so that they appear one after the other like this?
The Beatles
All You Need Is Love
www.songurl.com
Thank you!!
You can use the index to render the other data. Try
render(){
return(
<div>
{this.props.artist.map((artist, i) =>{
return(
<div key={i}>
<h3>{artist}</h3>
<h3>{this.props.title[i]}</h3>
<h3>{this.props.link[i]}</h3>
</div>
)
})}
</div>
)
}
You can put them all together in one map like this:
render(){
return(
<div>
{
this.props.artist.map((artist, i) =>{
return(
<div key={i} className="artist">
<h3>{artist}</h3>
<h3>{this.props.title[i]}</h3>
<h3>{this.props.link[i]}</h3>
</div>
)
})
}
</div>
)
}

How do I resolve React JSX's adjacent component wrapper error when I need to dynamically add markup in between elements?

I have a TypeList component that will show Type components in a table view like so:
I need to give the TypeList CSS with display: table and then add rows for every three types that are listed, so every three types need to be nested inside a <div class="table-row"></div>. I tried to do this with the logic below but get the adjacent JSX error. Is there something I can change to solve this?
TypeList.js
import Type from './Type'
const TypeList = ({info}) => (
<ul className="table">
<div class="table-row">
{
info.map(function (type, idx) {
// onclick details taken care of here
if (idx === map.length - 1){
return (
<Type key={idx} name={type.name} />
</div>
)
} else if (idx === 2) {
return (
<Type key={idx} name={type.name} />
</div>
<div class="table-row">
)
} else {
return (<Type key={idx} name={type.name} />)
}
})
}
</ul>
)
It's a bit ugly but it's the only solution I've found for problems like this.
function renderstuff(...) {
return (
<div>
(...)
</div>
).props.children;
}
This function renders your things in a <div> wrapper and then strips off the wrapper by returning .props.children.
It might work in your case, just extract the contents of your .map callback into a function, wrap your markup and return props.children of the wrapper.
I have rewritten the map function so that you don't have this error:
const TypeList = ({info}) => (
<ul className="table">
<div class="table-row">
{
info.splice(0, 2).map(function (type, idx) {
return <Type key={idx} name={type.name} />;
})
}
</div>
<div class="table-row">
{
info.map(function (type, idx) {
return (
<Type key={idx} name={type.name} />
);
})
}
</div>
</ul>
)

Categories