Nested If and map use in reactjs? - javascript

This is my following code:-
if(this.props.buttons && this.props.buttons.tabs && this.props.buttons.tabs.length) {
this.props.buttons.tabs.map((button) => {
return (
<TabsPanel label={button.labelKey} />
button.subtabs.map((subtab) => {
return(
<Tabs>
<TabsPanel label={subtab.labelKey}></TabsPanel>
</Tabs>
)
})
)
});
}
While running this following code it's always giving Syntax Error.
Here's my following JSON which I am getting
"tabs" : [
{
"labelKey" : "label1",
"subtabs" : [
{
"form" : {
"labelKey" : "subtab1"
}
},
{
"form" : {
"labelKey" : "subtab2"
}
}
]
},
{
"labelKey" : "label2"
}
]
Any leads would be helpful. I am stuck at a dead end right now.
Thanks!

The question is not very clear. But here are a few scenarios that I think could be intended.
TabsPanel component accepts Tabs as children:
Answer by Prabin is as correct as it gets. (Except for missing key attributes in TabsPanel and Tabs components)
TabsPanel component and Tabs list go side by side:
Note: A valid component is either one single root, or it is a list of other valid components.
So either this is correct.
this.props.buttons.tabs.map((button, index) => {
return (
<div key={index}>
<TabsPanel label={button.labelKey} />
{button.subtabs.map(subtab => {
return (
<Tabs key={subtab.labelKey}>
<TabsPanel label={subtab.labelKey} />
</Tabs>
)
})}
</div>
)
})
Or this is correct.
this.props.buttons.tabs.map((button, index) => {
return [
<TabsPanel label={button.labelKey} key={index} />,
{
...button.subtabs.map(subtab => {
return (
<Tabs key={subtab.labelkey}>
<TabsPanel label={subtab.labelKey} />
</Tabs>
)
})
}
]
})
Also, note the key attribute in Tabs and TabsPanel components. That is important and I leave it up to you to find it's importance.

return (
<div>
{this.props.buttons && this.props.buttons.tabs && this.props.buttons.tabs.length &&
this.props.buttons.tabs.map(button => {
return (
<TabsPanel label={button.labelKey}>
{button.subtabs.map(subtab => {
return (
<Tabs>
<TabsPanel label={subtab.labelKey} />
</Tabs>
);
})}
</TabsPanel>
);
})}
</div>
);
Try this should solve your problem

Related

React Component inside .map() is throwing an error: TypeError: notes.map is not a function

am trying to show Noteitem component which is returned inside a map function.
{notes.map((note) => {
return (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
);
})}
notes should be an array for map function to work. You can check it in following way if notes is not null and is an array using notes.length and apply map function
{notes && notes.length && notes.map((note) => {
return (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
);
})}
You can put if/else statement inside JSX to check the variable whether is exist or not
return (
<>
{
notes.length
? 'fallback'
: notes.map(note => <Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />)
}
</>
)
IIFE
{(() => {
if ("check note") {
// fallback
}
return notes.map((note: NoteProps) => (
<Noteitem key={note._id} updateNote={updateNote} showAlert={props.showAlert} note={note} />
));
})()}

How to properly destruct object within map function using javascript?

I would like to know how can i destruct object within .map function using javascript, i have react js component and within return method i have the code below:
return (
<>
{setItems.map(setItem => (
const { childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode} = setItem
....
</>
and i have the next error: Parsing error: Unexpected token ... = setItem, i thought what it is
EsLinterror and used // eslint-disable-next-line to disable it, but it didn't work.
UPD full return code:
return (
<div className={generalServiceItemClassName} key={guuid()}>
{setItems.map(setItem => (
const { childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode} = setItem
<div
key={guuid()}
className={cx(columnSizeClass, "service-items__item")}
data-test="service-items"
>
{setItem.learnMore ? (
<LearnMore
className="service-items__item-learn-more-container"
learnMoreLink={setItem.learnMore}
text={}
textClassName="service-items__item-texts-learn-more"
learnMoreText={learnNode ? learnNode.setItem : null}
>
{renderItem(setItem)}
</LearnMore>
) : (
renderItem(setItem)
)}
</div>
))}
</div>
)
You can't have a const declaration within an expression, and when you use the concise form of an arrow function (=> without a { after it), the body is an expression.
You can destructure in the parameter list, though. For instance:
{setItems.map(({childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode}) => (
// ...use `learnNode` here...
In context:
return (
<div className={generalServiceItemClassName} key={guuid()}>
{setItems.map(({childContentfulPartFeatureSetLearnMoreOptionalTextTextNode: learnNode}) => (
<div
key={guuid()}
className={cx(columnSizeClass, "service-items__item")}
data-test="service-items"
>
{setItem.learnMore ? (
<LearnMore
className="service-items__item-learn-more-container"
learnMoreLink={setItem.learnMore}
text={}
textClassName="service-items__item-texts-learn-more"
learnMoreText={learnNode ? learnNode.setItem : null}
>
{renderItem(setItem)}
</LearnMore>
) : (
renderItem(setItem)
)
}
</div>
))}
</div>
);
Try something like this. (destructure and renaming)
const setItems = [{ abc: 5 }];
return (
<>
{setItems.map((setItem) => {
const { abc: xyz } = setItem;
return <div>{xyz}</div>;
})}
</>
);
// Alternate way, simplified.
return (
<>
{setItems.map(({ abc: xyz }) => (
<div>{xyz}</div>
))}
</>
);

Destructuring argument for key along with object in javascript

How can I get the passed in object course along with the id key using destructuring the argument as in following code snippet ?
...
return (
<div>
{course.map(course => {
return <Course key={course.id} course={course} />;
})}
</div>
);
For instance I've tried like(see below) this, but its not valid
...
return (
<div>
{course.map(({id} = course) => {
return <Course key={id} course={course} />;
})}
</div>
);
The object for reference
const course = [
{
name: "Half Stack application development",
id: 1
},
{
name: "Node.js",
id: 2
}
Are there any way to do this or is it not possible yet?
Destructure id and spread the rest
course.map( ({ id, ...item }) => (
<div id={id}> {item.foo} </div>
))
You can't destruct an object into its an element and itself.
It could be better destruct item in the callback function like below.
console.log('-------Only get rest obj------');
const courses = [{ name: "Half Stack application development", id: 1 }, { name: "Node.js", id: 2 }];
courses.forEach(({id, ...item}) => console.log('rest obj:', item));
console.log('----Get full obj and destruct---------');
courses.forEach(item => {
const { id } = item;
console.log('id:', id);
console.log('item:', item);
});
return (
<div>
{course.map(item => {
return <Course key={item.id} course={item} />;
})}
</div>
);
You are trying to use the course variable again inside map function.
Rename outer most variable from course to courses.
return (
<div>
{courses.map(course => {
return <Course key={course.id} course={course} />;
})}
</div>
);
Consider below example
return (
<div>
{course.map(({ id, ...course }) => {
return <Course key={id} course={course} />;
})}
</div>
);
It does gets us the id but course object does have all the keys of the original object(ie, it doesn't have the id now).

How to map twice using Gatsby?

I want to create a table similar to how it's shown here ("Paslaugos" section), and allow the client to change table content using WordPress.
So I looped through, and displayed images and titles, without issue. However, I can't figure it out how to display table items. How do you map items twice in this context?
Update
{node.acf.table_items.header.map(({ c }) => (
<span>{c}</span>
))}
{node.acf.table_items.body[0].map(({ c }) => (
<span>{c}</span>
))}
So I kinda figure it out. This way would display header, but display only first item in the table. I need to loop body[0] in order to work, however I can't figure it out the exact syntax.
So thanks to ZeroToMastery forum the correct answer would be this:
{node.acf.table_items.body.map(mappingBody => {
return mappingBody.map(({ c, index }) => {
return (
<span key={index} className={classes.body}>
{c}
</span>
)
})
})}
Current Result
<StaticQuery
query={graphql`
{
allWordpressPost(
filter: {
categories: { elemMatch: { name: { eq: "favours" } } }
}
) {
edges {
node {
id
acf {
favours_title
table_items {
body {
c
}
header {
c
}
}
favours_images {
localFile {
childImageSharp {
fluid(maxWidth: 600) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
}
}
`}
render={data =>
data.allWordpressPost.edges.map(({ node }) => (
<div key={node.id} className={classes.item}>
<Img
className={classes.img}
fluid={
node.acf.favours_images.localFile.childImageSharp.fluid
}
/>
<h2 className={classes.title}>{node.acf.favours_title}</h2>
<div className={classes.grid}>
{node.acf.table_items.header.map(({ header }) => (
<span>{header}</span>
))}
{node.acf.table_items.body.map(({ body }) => (
<span>{body}</span>
))}
</div>
</div>
))
}
/>
I'm presuming that the data in body is a 2D nested array, e.g.
node.acf.table_items.body = [['row1-columnA', 'row1-columnB'], ['row2-columnA', 'row2-columnB']];
To map through each item in a 2D array, you could use map() twice:
{node.acf.table_items.body.map(c => c.map(el => (
<span>{el}</span>
)))}
Or, if you know there are a set number of items in each sub-array, you could use target the specific elements using square bracket notation:
{node.acf.table_items.body.map(c => (
<span>{c[0]}</span>
<span>{c[1]}</span>
))}
So thanks to Zero To Mastery forum, the correct answer would be this:
{node.acf.table_items.body.map(mappingBody => {
return mappingBody.map(({ c, index }) => {
return (
<span key={index} className={classes.body}>
{c}
</span>
)
})
})}

TypeError: Cannot read property 'map' of null

I couldn't understand why...here is the GitHub repository: https://github.com/Dronrom/React-test
That’s because you initialized peopleList as null in your component. So map works only on arrays so you need to check peopleList whether its really an array before doing map on it so
Change
renderItems(arr) {
return arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
}
To
renderItems(arr) {
if(arr){
return arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
}
}
I think your issue may be that react renders once before componentDidMount(). This is an issue because your calling map on arr which is null. const { peopleList } = this.state; you set people list to your current state which you set as default to be null, state = {peopleList: null}; then you later call this.renderItems(peopleList); which people list is still null at this moment so you are getting the Cannot read property 'map' of null error.
I belive something like componentWillMount is what you need instead. I recommend looking at this post which has a similar issue of react life cycle methods. React render() is being called before componentDidMount()
the answer is very simple: the type of the input isn't array type, it might be null or undefined. so that it doesn't have .map function.
How to fix:
Make sure your input must be array type before call renderItems().
render(){
const { peopleList } = this.state;
const items = (peopleList && peopleList.length) ? this.renderItems(peopleList) : null;
return(
<ul className="item-list list-group">
{items}
</ul>
);
}
Or:
Make sure your input must be array type before do mapping:
renderItems(arr) {
return !arr ? null : arr.map(({id, name}) => {
return (
<li className="list-group-item"
key={id}
onClick={() => this.props.onItemSelected(id)}>
{name}
</li>
);
});
{product.size?.map(c=>(
<FilterSizeOption key={c}>{c}</FilterSizeOption>
))}
Wrapping the return statement with a if statement worked for me
So changed
return (
<div>
<Navbar />
{countries.map((country, i) => {
return (
<div>
<span key={`${country.name.common}${i}`}>
{country.name.common}
</span>
</div>
);
})}
</div>
);
to this
if (countries) {
return (
<div>
<Navbar />
{countries.map((country, i) => {
return (
<div>
<span key={`${country.name.common}${i}`}>
{country.name.common}
</span>
</div>
);
})}
</div>
);
}

Categories