Using Array.map in React - javascript

I'm confused how this code work
const sidebar = (
<ul>
{
props.posts.map((post) =>
<li key={post.id}>
{post.title}
</li>
)
}
</ul>
);
I know that a map returns an array, but how can it return all these tags
<li key={post.id}>
{post.title}
</li>
and render it?
I have tried changing it to forEach but it's not working. Nothing displays on the UI:
const sidebar = (
<ul>
{
props.posts.forEach((post) =>{
return <li key={post.id}>
{post.title}
</li>
})
}
</ul>
);

The map() method creates a new array with the results of calling a
provided function on every element in the calling array.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
The forEach() method executes a provided function once for each
array element.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
This means if you try to return something in the method executed in forEach you are not creating an array of tags.
JSX is expecting an array of tags to be rendered but in forEach you are not creating an array you are just iterating over the array so JSX receives nothing at the end

Related

React render array to add to a list - simple return not working

I've created a simple object
const customer = { name : "foo", phone : "519-500-5000", orders : { crust: "normal", toppings : ["Cheese", "Bacon"]} }
it holds a internal object called "orders" that has also has an array of toppings, in these case "Cheese" and "Bacon".
I've extracted the array out and passed it into a render toppings function
renderToppings (toppings) {
console.log("render Toppings: ", toppings) // Renders the whole array of toppings, good.
toppings.forEach(function (topping) {
//return (
// <li> {topping} </li>
//)
console.log("each Topping: ", topping) // This DOES render each topping separately as expected.
});
}
I created a list that has other values, then I eventually called my render method (which is within the same class)
{this.renderToppings (PizzaToppings)}
the console log does return the values I was expecting. But when I uncomment out the return, it doesn't do the console nor does it print the the toppings.
What am I missing here? Sorry if this is all sloppy, I'm new to react.
You aren't returning to anything. The return value of a forEach() callback is not used.
Use map() instead to generate an array of your elements and return that
return toppings.map(function (topping) {
return (
<li> {topping} </li>
);
});
Demo
class Pizza extends React.Component {
render() {
var toppings = ['cheese', 'sausage', 'never pineapple'];
var elements = toppings.map(topping => {
return (
<li>
{topping}
</li>
);
});
return (
<ul id = "toppings">
{elements}
</ul>
);
}
}
ReactDOM.render(
<Pizza /> ,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
forEach doesn't return anything(returns undefined), you need to use map function
renderToppings (toppings) {
return toppings.map((topping) => {
return (
<li> {topping} </li>
)
});
}
You are using .forEach and a forEach only calls a given method on each item of the array and does nothing with the return value.
Use .map instead, map returns a new array. It also calls a method on each item in the array but allows you to return a new value for each item it iterates.
renderToppings (toppings) {
toppings.map(function (topping) {
return (
<li> {topping} </li>
)
});
}
Would work in your case
The callback in .forEach modifies the original array, but for React to render the element you should create a new array with .map

React map with opening and closing tags

So i want to print a group of nested lists with react components around certain elements.
the array looks like this (with 1 and -1 indicating to move deeper in levels):
const linkArray = ['value','another value',1,'third value',-1,'fourth value']
which i want to render like
<ol>
<li><SomeComponent>value</SomeComponent></li>
<li><SomeComponent>another value</SomeComponent></li>
<ol>
<li><SomeComponent>third value</SomeComponent></li>
</ol>
<li><SomeComponent>fourth value</SomeComponent></li>
what i have now is:
<ol>{linkArray.map(link =>{
if (link == 1) {
return <ol>;
} else if (link == -1) {
return </ol>;
}
else
return <li><SomeComponent>{link}</SomeComponent></li>;
})}
</ol>
this won't compile and i'm assuming it's because you can't just include an opening tag without a closing tag in map.
Neither <ol> nor </ol> are valid JSX, which is why your current code fails.
My advice would be to reshape your data structure such that you are not relying on the 1 and -1 to tell you when to go up or down a level in nesting. Something like this would be easier to work with:
const linkArray = ['value', 'another value', ['third value'], 'fourth value']
This way, your data structure has the same shape as the desired output.
From here, we can define a recursive function, which will render a new <li> element when it encounters a string, and a new <ol> element when it encounters an array:
const nestedList = link => {
if (link instanceof Array) {
return <ol>{link.map(nestedList)}</ol>;
} else {
return <li>{link}</li>;
}
}
Then return the following in your main component's render method (a call to the function we just defined wrapped in an outer set of <ol> tags):
<ol>{linkArray.map(nestedList)}</ol>
The following HTML is rendered:
<ol>
<li>value</li>
<li>another value</li>
<ol>
<li>third value</li>
</ol>
<li>fourth value</li>
</ol>
Which is the desired output (minus the <SomeComponent> tags, which I left out for simplicity's sake - they don't affect the logic).

Using a map within a map in jsx

{normalizedData.map(obj =>
<div key={obj.display_date_numberic}>
<div>{obj.display_date_numberic}</div>
</div>
{!isEmpty(obj.applicants) && obj.map(obj2 =>
<div className="events">{obj2.person.name}</div>
)}
)}
I'm getting an error on the following line:
{!isEmpty(obj.applicants) && obj.map(obj2 =>
Why can't I use the map function inside another map? normalizedData has an array of objects and each obj has another array of objects.
You can do a map within a map as follows:
e.g. given data of
outerArray: [
{ id: '1st', innerArray: [ 'this', 'that' ]},
{ id: '2nd', innerArray: [ 'some', 'what' ]},
]
you can use JSX:
<ul>
{outerArray.map(outerElement => {
return outerElement.innerArray.map(innerElement => (
<li key={outerElement.id}>
{innerElement} - {outerElement.id}
</li>
))
})}
</ul>
or slightly more succinctly:
<ul>
{outerArray.map(outerElement => (
outerElement.innerArray.map(innerElement => (
<li key={outerElement.id}>
{innerElement} - {outerElement.id}
</li>
))
))}
</ul>
which renders:
<ul>
<li>this - 1st</li>
<li>that - 1st</li>
<li>some - 2nd</li>
<li>what - 2nd</li>
</ul>
note the use of key= inside the map to ensure React has a unique reference for the element from each loop iteration. If you don't it will warn you!
Reason is, you are trying to render more than one element, and we can't do that, we can return only one element. So wrap all the logic and elements inside one div like this:
{normalizedData.map(obj =>
<div key={obj.display_date_numberic}>
<div>{obj.display_date_numberic}</div>
{Array.isArray(obj.applicants) && obj.applicants.map(obj2 =>
<div className="events">{obj2.person.name}</div>
)}
</div>
)}
Assuming obj.applicants is an array, use Array.isArray to check whether any value is a proper array or not
Note: We can use map only on array not on any object, so if obj is an object and use Object.keys(obj) to get an array of all the keys then use map on that.
The evident error that you hace in your code is that , you should be mapping on obj.applicants in the inner map and not obj and return a single element from the outer map
Also if obj.applicants is an array, no need to use isEmpty
{normalizedData.map(obj =>
<div>
<div key={obj.display_date_numberic}>
<div>{obj.display_date_numberic}</div>
</div>
{ obj.applicants.map(obj2 =>
<div className="events">{obj2.person.name}</div>
)}
</div>
)}
Just advice, you can use for instead of map

List elements not rendering in React [duplicate]

This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 26 days ago.
This is my Sidebar component.
const Sidebar = React.createClass({
render(){
let props = this.props;
return(
<div className= 'row'>
<h2>All Rooms</h2>
<ul>
{props.rooms.map((room, i) => {
<li key={i}> {room.name} </li>
})}
</ul>
{props.addingRoom && <input ref='add' />}
</div>
);
}
})
This is where I render it populating one room.
ReactDOM.render(<App>
<Sidebar rooms={[ { name: 'First Room'} ]} addingRoom={true} />
</App>, document.getElementById('root'));
The contents inside the <ul></ul> tag don't render at all. Any idea what I could be missing.
You aren't returning anything from the map function, so it renders nothing inside the unordered list. In your arrow function, you do:
(room, i) => {
//statements
}
This doesn't return anything. Array.prototype.map requires a callback that returns a value to do anything. map transform elements to the array, mapping (executing) the callback on each element. The return value is what the value is in the corresponding position in the returned and mapped array.
You must return the list element in the map function like so:
<ul>
{props.rooms.map((room, i) => {
return <li key={i}> {room.name} </li>;
})}
</ul>
Now, the mapped array of list elements is rendered because the list element is returned.
To make this shorter, you may write it in the form (params) => value which is equivalent to the above, where value is the returned value, like so:
{props.room.map((room, i) => <li key={i}> {room.name} </li>)}

Create html structure which will allow only 3 div elements in each li. In React + underscore.js

This is bit copy of How to create html structure which will allow only 3 div elements in each li. In React + underscore.js
Actually i am facing issue while iterating array in li.
I have below array structure
var xyz = [{'name': ['abc','xyz','test','test1','test2','test3','test4'] }];
and i want below output structure
<ul>
<li>
<div><span>test3</span></div>
<div><span>test4</span></div>
<div><span>test5</span></div>
</li>
<li>
<div><span>test6</span></div>
<div><span>test7</span></div>
<div><span>test8</span></div>
</li>
I am using React and underscore.js on my project.
I want everything in pure react function I tried to append li's into ul as a string but that is bad practice it react.js
Can anyone help me in this.
Using below function i have created array structure which will contain 3 values in one array object.
var n = 3;
var chunkedlists = _.chain(this.state.serialIdFilter).groupBy(function(element, index){
return Math.floor(index/n);
}).toArray().value();
Now i want help in printing this into proper structure as i mentioned using react + underscore.js.
const Com = () => {
var xyz = [{'name': ['abc','xyz','test','test1','test2','test3','test4'] }];
return (
<ul>
{_.map(_.chunk(xyz[0].name, 3), (innerItem, i) => (
<li key={i}>
{_.map(innerItem, (name, j) => (<div key={j}><span>{name}</span></div>))}
</li>
))}
</ul>
);
}
ReactDOM.render(<Com />, document.getElementById("container"));
An example bin an be found here:
http://jsbin.com/menidu/4/edit?js,output
something like this would be required
return (
<ul>{chunkedLists.map(group => <li>{group.map(i => <div><span>{i}</span></div>)}</ul>)}
)

Categories

Resources