React render quantity of components based on a numeric value - javascript

I want to pass in a value to a component and render multiple child components based on that value. e.g. if I pass in count={4} in props, then I want to render 4 <Icon/> components. If I pass in 5, I want to render 5, and so on.
At the moment, all I can think to do is to take the value and turn it into an array (i.e. do a for loop and push a placeholder element to an array with each iteration) and then do a map on that array. But that seems like overkill.
Is there a simple solution to this?

You can do it like this:
...
return(
Array.from({length: props.count}, () => <Icon />)
)

You're probably looking a way to map amount of children to be populated. Check this live example: https://snack.expo.io/#zvona/mapping-child-components
This is the core code from that example:
const Icon = ({index}) => (
<View><Text>{`Icon #${index + 1}`}</Text></View>
);
const Icons = ({count}) => (
Array.from({length: count}).map((_item, index) => <Icon index={index}/>)
)
const App = () => {
return (
<View style={styles.container}>
<Icons count={5} />
</View>
);
}

You can use a simple for loop for this
for(let i = 0; i < count ; i++){
return <Icon />
}
If this doesn't work, you can do the following. It's a bit modern es6 function. Try this..
{[...Array(count)].map((x, i) =>
<Icon key={i} />
)}

Related

Mapping through objects and render in React Native

I have a React Native project where i am getting object like the attached image. I need to map through them and render description and rate from them.
How can i acheive this. I have been trying with Object.keys but not been able to do it. Here's what i have tried. Don't know if it makes sense:
{Object.keys(myObject).map(function(key, index) {
return (
<Text>
{myObject.map((rate, description) => {
return (
rate,
description
)
})
</Text>
}
If you're just trying to map the rate and description, you don't need the second map -- you can just use the key to get the entry from the original object and then access its properties directly:
{Object.keys(myObject).map(key => {
const item = myObject[key];
return (<View>
<Text>{item.rate}</Text>
<Text>{item.description}</Text>
</View>
)})}
You can not use map on objects so try with bellow code
<>
{Object.keys(myObject).map((key, index)=>
<Text>{myObject[key].description}, {myObject[key].rate}</Text>
)
}
</>

React incrementing variable within .map() function

I am mapping through an array, and I want my variable i to be used as a unique key for my Components, however I do not know how (or where) to increment it correctly, if I add a {i++} within the <Component> tags then it will display the value of i on screen, and if I instead add {this.function(i)} and place the i++ inside the function, it will call the function but the variable i will reinitiate to the value of 0 everytime, so the key value will not be unique. I need the value of i to be the key for the component and it has to be incremented by 1 everytime, does anyone know how I can achieve this? Also, as you can see in the code, when the component is clicked it will make a function call which will send the value of i of the clicked component as a parameter to the called function.
Code:
function(i) {
console.log(i)
}
render() {
var i = 0;
var {array} = this.state;
return (
<div className="App">
{array.map(item => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
))}
</div>
);
}
The map function gets a second parameter which is the index of the element:
{array.map((item, i) => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
)}
Be aware that if you intend to sort this array or change its contents at runtime, then using array index as a key can cause some mistakes, as sometimes an old component will be mistake for a new one. If it's just a static array though, then using index as a key shouldn't be a problem.
.map already offer the increment, just add a second variable to the callback
render() {
var {array} = this.state;
return (
<div className="App">
{array.map((item,i) => (
<Component key={i} onClick={(e) => this.function(i, e)}>
<p>{item.name}</p>
</Component>
))}
</div>
);
}
You could try array.map((x, Key) => console.log(key)); ..
In place of console.log you could add your code, it should work fine as per your requirement.

How to repeat one element in JSX?

I want repeat one image element in JSX, my required code is like as below:
<View>
<Image source={require('../images/image.png')} />
<Image source={require('../images/image.png')} />
<Image source={require('../images/image.png')} />
<Image source={require('../images/image.png')} />
<Image source={require('../images/image.png')} />
</View>
How i can use a loop to generate this code?
Easy! You can create an array on the fly. Like this:
<View>
{[...Array(5)].map((x, i) => <Image key={i} source={require('../images/image.png')} />)}
</View>
The [...Array(5)] gives: [undefined, undefined, undefined, undefined, undefined]. Which might look useless, but actually, this gives us something to iterate over with map() which we can use to return the Components we want (we don't need x here at all).
You could, to improve performance, create the array outside your render to prevent re-creating the temporary array on each re-render. You can also put your require separately for similar reasons.
You can store it in a variable before you return your jsx.
Example:
const myjsx = [];
for(let i = 0; i < 4; i++) {
myjsx.push(<Image source={require('../images/image.png')} />);
}
then in your final JSX you simply print out the {myjsx}
<View>
{myjsx}
</View>
You can create a short function to do this for you
let func = () => (<Image source={require('../images/image.png')} />)
<View>
{func()}
{func()}
{func()}
{func()}
{func()}
</View>
You can add a loop or perform additional refactorings from there.
Try this:
const totalImages = 10;
<View>
{
(new Array(totalImages)).fill(<Image source={require('../images/image.png')}/>)
}
</View>
You can create a function that loops and returns the elements in question.
renderImages() {
var images = [];
for (var i = 0; i < numrows; i++) {
images.push(<Image source={require('../images/image.png')} />);
}
return images;
}
In the render method you would just call the function name as such:
{renderImages()}
<View>
{() => {
const
longArray = new Array(7),
image = require('../images/image.png');
return longArray.map((k, i) => <Image key={k} source={image} />);
}}
</View>

javascript React Native

Hi (Sorry for my english)
I have a problem, I consume a service that bring me a buttons array for a dynamic menu. This array I want to put in the screen, like button have a id for a action in specific.
Code
var sizes = []
for (var i = 0; i < this.state.tallas.length; i++) {
sizes.push(
<TouchableOpacity style={[styles.clothingSizeItem, this.state.idSize === this.state.tallas[i].id ? styles.activeClothingSizeItem:null]}
onPress={() => this.fetchSizeData(this.state.tallas[i].id)}>
<Text style={this.state.idSize === this.state.tallas[i].id ? styles.activeSizeText:null}>
{this.state.tallas[i].name}
</Text>
</TouchableOpacity>
);
}
View
render() {
return(
{sizes}
)
}
The problem is when I press a button from my dinamic menu, the button call a function that receive a parameter, but this parameter comes from service array. So I use "i" param from for, but this variable ("i") can't found after that the screen was rendered.
Screen Shot
error screen
Gracias!
You can use Array#map instead of a for loop:
const sizes = this.state.tallas.map(item => (
<TouchableOpacity style={[styles.clothingSizeItem, this.state.idSize === item.id ? styles.activeClothingSizeItem:null]}
onPress={() => this.fetchSizeData(item.id)}>
<Text style={this.state.idSize === item.id ? styles.activeSizeText:null}>
{item.name}
</Text>
</TouchableOpacity>
);
The reason the for loop doesn't work here is that the index variable i is incremented on every iteration of the loop, so by the time the callback ends up being called (long after the loop has completed), the value i is always it's final value (same as tallas.length).

Rendering React Components from Array of Objects

I have some data called stations which is an array containing objects.
stations : [
{call:'station one',frequency:'000'},
{call:'station two',frequency:'001'}
]
I'd like to render a ui component for each array position. So far I can write
var stationsArr = []
for (var i = 0; i < this.data.stations.length; i++) {
stationsArr.push(
<div className="station">
{this.data}
</div>
)
}
And then render
render(){
return (
{stationsArr}
)
}
The problem is I'm getting all of the data printing out. I instead want to just show a key like {this.data.call} but that prints nothing.
How can I loop through this data and return a new UI element for each position of the array?
You can map the list of stations to ReactElements.
With React >= 16, it is possible to return multiple elements from the same component without needing an extra html element wrapper. Since 16.2, there is a new syntax <> to create fragments. If this does not work or is not supported by your IDE, you can use <React.Fragment> instead. Between 16.0 and 16.2, you can use a very simple polyfill for fragments.
Try the following
// Modern syntax >= React 16.2.0
const Test = ({stations}) => (
<>
{stations.map(station => (
<div key={station.call} className='station'>{station.call}</div>
))}
</>
);
// Modern syntax < React 16.2.0
// You need to wrap in an extra element like div here
const Test = ({stations}) => (
<div>
{stations.map(station => (
<div className="station" key={station.call}>{station.call}</div>
))}
</div>
);
// old syntax
var Test = React.createClass({
render: function() {
var stationComponents = this.props.stations.map(function(station) {
return <div className="station" key={station.call}>{station.call}</div>;
});
return <div>{stationComponents}</div>;
}
});
var stations = [
{call:'station one',frequency:'000'},
{call:'station two',frequency:'001'}
];
ReactDOM.render(
<div>
<Test stations={stations} />
</div>,
document.getElementById('container')
);
Don't forget the key attribute!
https://jsfiddle.net/69z2wepo/14377/
I have an answer that might be a bit less confusing for newbies like myself. You can just use map within the components render method.
render () {
return (
<div>
{stations.map(station => <div key={station}> {station} </div>)}
</div>
);
}
this.data presumably contains all the data, so you would need to do something like this:
var stations = [];
var stationData = this.data.stations;
for (var i = 0; i < stationData.length; i++) {
stations.push(
<div key={stationData[i].call} className="station">
Call: {stationData[i].call}, Freq: {stationData[i].frequency}
</div>
)
}
render() {
return (
<div className="stations">{stations}</div>
)
}
Or you can use map and arrow functions if you're using ES6:
const stations = this.data.stations.map(station =>
<div key={station.call} className="station">
Call: {station.call}, Freq: {station.frequency}
</div>
);
This is quite likely the simplest way to achieve what you are looking for.
In order to use this map function in this instance, we will have to pass a currentValue (always-required) parameter, as well an index (optional) parameter.
In the below example, station is our currentValue, and x is our index.
station represents the current value of the object within the array as it is iterated over.
x automatically increments; increasing by one each time a new object is mapped.
render () {
return (
<div>
{stations.map((station, x) => (
<div key={x}> {station} </div>
))}
</div>
);
}
What Thomas Valadez had answered, while it had provided the best/simplest method to render a component from an array of objects, it had failed to properly address the way in which you would assign a key during this process.
There are couple of way which can be used.
const stations = [
{call:'station one',frequency:'000'},
{call:'station two',frequency:'001'}
];
const callList = stations.map(({call}) => call)
Solution 1
<p>{callList.join(', ')}</p>
Solution 2
<ol>
{ callList && callList.map(item => <li>{item}</li>) }
</ol>
Of course there are other ways also available.

Categories

Resources