How can I display count of mapped looped items in React - javascript

Notice in the code sample below that I'm mapping all the data into ResultItems
{store.results.data.map( result =>
<ResultItem key={result.id}
title={result.title}
description={result.description}
start_date={result.start_date}
end_date={result.end_date}
vendor_name={result.vendor.name}
buyer_name={result.buyer.name}
preview_file={result.preview_file}
status={result.status}
/>)}
what I want to do is keep count of how many resultitems there are and display that number in the DOM
Any ideas on how to do that?

Use the length of the array to know how many items the array has or if you want to access each one just use the index of the map function.
const length = store.results.data.length
{store.results.data.map( (result, index) =>
<ResultItem
position={index}
(...)
/>
)}

Related

What should I use as a key for "row" elements in react?

I have a gallery that displays a number of books per row. This gallery takes an array of books as a prop and uses "itemsPerRow" prop to chunk the books into a 2 dimensional array and then loops through all the books to display the books in a grid-like structure.
export default function Gallery({ items, itemsPerRow, renderLink }) {
itemsPerRow = itemsPerRow ?? 3
const rows = chunk(items, itemsPerRow)
const renderEmptyItems = (itemsToRender) => {
const items = []
for(let n = itemsToRender; n > 0; n--) {
items.push(<GalleryItem key={`empty_${n}`} empty/>)
}
return items
}
return (
<div>
{
rows.map((row, index) => (
<div key={index} className="tile is-ancestor">
{row.map(item => <GalleryItem key={item.id} renderLink={renderLink} {...item}/>)}
{/* Add empty gallery items to make rows even */}
{index + 1 === rows.length && renderEmptyItems(itemsPerRow - row.length)}
</div>
))
}
</div>
)
}
However, unless I give each div representing a row a key, react complains about the lack of keys. As I understand it, using the index as a key doesn't really help react and should be avoided. So what should I use as a key here <div key={index} className="tile is-ancestor"> instead of the index?
Use a unique identifier (book.id, maybe book.title if it's unique) for the key props. If your data does not have a unique identifier, it's okay to use index.
You need to specify a value that uniquely identify the item, such as the id. You can read more about keys in the documentation.
Also it is not recommended to use indexes as keys if the order of your data can change, as React relies on the keys to know which components to re-render, the documentation I linked explains that further.
You can use the unique_identifier which differentiate each of the documents(probably, you should pass the document _id as a key prop in the row components)
<div className="row">
{notes.map((item) => {
return (
<div key={note._id} className="col-md-6">
<Component item={item} />
</div>
);
})}
</div>

How to loop through new input boxes renderer in React and get the values in an array?

I need to dynamically generate multiple divs with a single input-box in it, so the user can add a number.
The user can add by clicking a button, any number of divs with input-box to put a number in it.
After the user end with the entry of the data, must click a button to process the data.
I've find out how to use React to iterate through an existing array, but not about how to iterate through a new DOM tree that was created dynamically by the user, and then generate an array with the values inside all the input-boxes.
After processing, different values will be displayed (max value, min value, average, return results from equations, etc)
Without seeing your code it's hard to help, but you probably want to use controlled inputs rather than uncontrolled ones, and so you'd have an array of the current values for the inputs as state information.
For instance, in a functional component using hooks:
const { useState } = React;
function Example() {
// The values we use on the inputs
const [values, setValues] = useState([]);
// Update the value at the given index
const updateValue = (value, index) => {
setValues(values =>
Object.assign([], values, {[index]: value})
);
};
// Add an input
const addInput = () => {
setValues(values => [...values, ""]);
};
// Get the sum (just an example; and one of the very few places I'll use `reduce`)
const sum = values.reduce((sum, value) => sum + Number(value), 0);
// Render as many inputs as we have values, along with the
// button to add an input and the sum
return (
<div>
<div>
{values.map((value, index) =>
<div key={index}>
<input type="text" value={value} onChange={evt => updateValue(evt.target.value, index)} />
</div>
)}
</div>
<div>Sum: {sum}</div>
<input type="button" value="Add Input" onClick={addInput} />
</div>
);
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
I think you could just create one div, and an array to store the values, then create a function that everytime the user choose to add a new value, it saves the current on that array and clean the input. So, when the user select to process the data it takes that array and do what you need.

How to start mapping a nested json from a certain index and map it back to that index-1 value

I want to map my nested json from a certain index
For example if my json is the following:
{"data":[{id:1,name:"NAV"},{id:2,name:"Rick"},{id:3,name:"Ceil"}]}
I want to start mapping this json from 1st index i.e. id =1 name :rick
and map it till nav so the mapping is in the following order:
{id:2,name:"Rick"}
{id:3,name:"Ceil"}
{id:1,name:"NAV"}
Something like a circular array or queue
I have no idea how to implement this mapping in react native or js.
How I am currently mapping my json
renderArtciles=()=>{
return this.state.dataSource.map((item,i)=>{
<Animated.View key={item._id} >
<View style={styles.Imagebody}>
<Image source={{ uri:item.img.data }} style{styles.image}/>
</View>
<View style={styles.inner}>
<ShareItem id={item._id} />
<View style={styles.inner}>
<Text style={styles.titleArrtibute}>Trending</Text>
<Text style={styles.titleText} >{item.title}</Text>
<View>
<Text style={styles.body}>{item.body}</Text>
</View>
</View>
</View >
</Animated.View>
});
}
Here's a quick way to pop off the first element from an array and push it to the back.
Note: These examples modify the original collection.
If you do not want to modify the original you will need to create a clone of the array first. Or you can go with the "walking the array" approach I've added below.
Overall I do not think you are looking to map in this instance, the real question seems to be sorting or iterating your array in a specific way where it loops.
Once you have sorted or iterated your array you can then do your mapping to extract the data you are after.
Example - Rotate a Single Element
const cats = ['Bob', 'Willy', 'Mini'];
cats.push(cats.shift());
console.log(cats);
Example - Rotate Multiple Elements
This is if you want to cycle more than 1 element from the front to the back of the array (an example has been attached at the bottom to demonstrate cloning an array).
This will cut off the given amount (2 in this example) and then uses the spread operator to push the new cut off items from the array back into the array. We use the spread operator because splice returns an array and we don't want a jagged semi-multidimensional array.
const cats = ['Bob', 'Willy', 'Mini', 'Dingus'];
cats.push(...cats.splice(0, 2));
console.log(cats);
Example - Nested Data
Since Javascript stores objects by reference we can store variables and apply the same techniques from above to directly modify the original object.
ie: Notice how we assign a new variable data and modify it but log the original object namesInData which is now changed.
const namesInData = {data:[{name: 'Bob'}, {name: 'Willy'}, {name: 'Mini'}]};
const data = namesInData.data;
data.push(data.shift());
console.log(namesInData);
Example - Walking the Array with a For Loop & Offset
We use the modulus operator % so that when i blows past the end of the array it will wrap back to the front.
const cats = ['Bob', 'Willy', 'Mini', 'Dingus'];
const start = 2;
const length = cats.length;
for(let i = start; i < length + start; i++) {
console.log(cats[i % length]);
}
Cloning an Array
If you do not want to modify the original array you will need to clone it first.
ES6 Way 🎉
Using the spread operator we can assign the spread to a new array.
const data = [...originalData];
Older Non ES6
const data = originalData.slice();
Additional Resources
Pop, Push, Shift, and Unshift Array
Array.prototype.splice not to be confused with slice which does not modify the original array.
Cloning an array
You can do it with just the map function if you find the starting index first.
Note: This solution does not modify the array.
const { dataSource } = this.state
// set startingIndex using whatever method you have
// to find the index of the first item
const startingIndex = (dataSource.findIndex(item => item.name === 'NAV') + 1) % dataSource.length
// underscore to ignore the current item,
// since we'll index to a different item instead
return dataSource.map((_, index) => {
const shiftedIndex = (startingIndex + index) % dataSource.length
const item = dataSource[shiftedIndex]
return {/* render code */}
})
I don't know if there's a way to do it with .map (my instinct is no) but you could do something like the below with a for loop:
let index = 1; //whatever index you want to start from
for (let i = 0; i < data.length; i++) {
//do all of your stuff referencing data[index] not data[i]
//at the end of whatever do:
index === data.length - 1 ? index = 0 : index++;
}
Give it a go, something along these lines should work.
Note: This uses the array index, and not your object id.

Map from-to using react.js

I have a map loop that returns a list of values eg 0 - 100. The problem is that this will return the whole list. I want to only return a specific number of values. eg (11-20). What would be the best way of implementing this?
The current code is
const all = this.props.memories.map((value, index) => {
return (
<div>
{value}
</div>
)
})
Use .slice() as this.props.memories.slice(11, 20).map...
Slice ..Use it when you do not want to alter the original contents, instead a shallow copy of that for local change and usage.
this.props.memories.slice(11,20).map((value, index) => {
return (
<div>{value}</div>
)
})

Is it possible to map only a portion of an array? (Array.map())

I am building a project using React.js as a front-end framework. On one particular page I am displaying a full data set to the user. I have an Array which contains this full data set. It is an array of JSON objects. In terms of presenting this data to the user, I currently have it displaying the whole data set by returning each item of data using Array.map().
This is a step in the right direction, but now I need to display only a portion of the data-set, not the whole thing, I also want some control in terms of knowing how much of the total data set has been displayed, and how much of the data set is yet to be displayed. Basically I am building something like a "view more" button that loads more items of data to the user.
Here is what I am using now where 'feed' represents my Array of JSON objects. (this displays the whole data set.)
return (
<div className={feedClass}>
{
feed.map((item, index) => {
return <FeedItem key={index} data={item}/>
})
}
</div>
);
I am wondering if it is possible to use .map() on only a portion of the array without having to break up the array before hand? I know that a possible solution would be to hold the full data set, and break it off into portions, and then .map() those portions, but is there a way to .map() a portion of the array without having to break it up?
Any and all feedback is appreciated. Thanks!
Do not try to solve this problem with a hack in your mapping step.
Instead, slice() the list to the right length first before the mapping:
class Feed extends React.Component {
constructor(props) {
super(props)
this.handleShowMore = this.handleShowMore.bind(this)
this.state = {
items: ['Item A', 'Item B', 'Item C', 'Item D'],
showItems: 2
}
}
handleShowMore() {
this.setState({
showItems:
this.state.showItems >= this.state.items.length ?
this.state.showItems : this.state.showItems + 1
})
}
render() {
const items = this.state.items.slice(0, this.state.showItems).map(
(item) => <div>{item}</div>
)
return (
<div>
{items}
<button onClick={this.handleShowMore}>
Show more!
</button>
</div>
)
}
}
ReactDOM.render(
<Feed />,
document.getElementById('root')
)
<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='root'></div>
The easiest way in my head is just to use a filter and map
const feed = [1,2,3,4,5,6,7,8,9,10,11]
feed.filter((item, index) => index < 5).map((filteredItem) => //do somthing with filtred item here//)
where 5 is just a number of items you want to get
you could use the slice function before to map the array, it looks like you want to do some pagination there.
var fruits = ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango'];
var citrus = fruits.slice(1, 3);
// fruits contains ['Banana', 'Orange', 'Lemon', 'Apple', 'Mango']
// citrus contains ['Orange','Lemon']
Array.reduce should do what you're asking for. Just change the if statement depending on which range you want.
var excludeAfterIndex = 5;
feed.reduce((mappedArray, item, index) => {
if (index > excludeAfterIndex) { // Whatever range condition you want
mappedArray.push(<FeedItem key={index} data={item}/>);
}
return mappedArray;
}, []);
If you just want to map a portion of an array, you should first filter() your array to obtain the expected portion according to conditions :
array.filter(item => <condition>).map();
Yes, you can map portion of array, based on index. For example:
yourArray = yourArray.map(function (element, index, array) {
if (array.indexOf(element) < yourIndex) {
return {
//logic here
};
} else {
return {
//logic here
};
}
});
You can use slice to get portion of an array:
const data = [1,2,3,4,5,6,7,8,9,10,11]
var updatedData = data.slice(0, 3);
Array#map iterates over all items.
The map() method creates a new array with the results of calling a provided function on every element in this array.
You could use Array#filter
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
for the wanted items and then apply map for the wanted format.
There is no version of the map() function that only maps a partial of the array.
You could use .map() in conjunction with .filter().
You get the index of the current element as the second arg of map and if you have a variable for current page and page size you can quite easily filter the right page from your array without having to really slice it up.
var currentPage = 1;
var pageSize = 25;
dataArray.filter(function(elt, index) {
var upperThreshold = currentPage * pageSize;
var lowerThreshold = currentPage * pageSize - pageSize;
return index < upperThreshold && index > lowerThreshold;
});
Using slice() is better than adding a condition to your map or reduce function, but it still creates an additional, unused copy of that segment of the array. Depending on what you're doing, that might not be desired. Instead, just use a custom map function:
function sliceMap(fn, from, toExclusive, array) {
const len = toExclusive - from;
const mapped = Array(len);
for (let i = 0; i < len; i++) {
mapped[i] = fn(array[i + from], i);
}
return mapped;
};
Note that fn receives the array value and the (now) zero-based index. You might want to pass the original index (i + from). You might also want to pass the full array as a third parameter, which is what Array.map does.
Use this, easy approach
const [limit, setLimit] = useState(false);
const data = [{name: "john}, {name: 'Anna'}]
Here we will have 2 cases:
Display only first data which is John
Display all
data.slice(0, extended ? data.length : 1).map((item, index) => <Text>{item.name}</Text>)
....

Categories