My task is to add a number to an array if it is unique.
const [items, setItems] = useState(new Set());
const addNumber = () => {
//add elements to an array if it is unique
//is below line is right way to add element ? or i have to write like this - setItems(items.add(input)) ??
items.add(input);
};
<button onClick={addNumber}>ADD Number</button>;
// trying to display the set data, throws an error:map is not a function
<ul>
{
items.map(item=>(<li>{item}</li>))
}
I want to iterate through set to display the data. Thanks in advance.
There are a couple of ways to do this, first that comes to mind is, can you use a set rather than an array? Each element in a set is unique by default: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set
The second is to conditionally add items to the array by first testing if they exist eg
const addNumber = (number) => {
// findIndex will return -1 for items which don't already exist in the array
const index = items.findIndex(item => item === number)
if ( index === -1 ) {
// make a copy of the index array to mutate
const updatedItems = [ ...items ]
updatedItems.push(number)
setItems(updatedItems)
}
}
I wouldn't rely onto array length as it may change (items added and, what's worse, removed), so the simplest way would be to grab first unused id
or maximum used id
plus 1).
The latter would look as follows:
const addNumber = () => {
const ids = items.map(({id}) => id),
nextId = Math.max(...ids) + 1
setItems([
...items,
{
id: nextId,
value: input
}
])
}
The former, like this:
const addNumber = () => {
const ids = items.map(({id}) => id),
nextId = [...Array(x.length+1)]
.map((_,i) => i)
.find(n => !x.includes(n))
setItems([
...items,
{
id: nextId,
value: input
}
])
}
Following quick live-demo demonstrates the way of maintaining uniqueness of both record values and record id's:
const { useState } = React, { render } = ReactDOM, rootNode = document.getElementById('root') const App = () => { const [items, setItems] = useState([]), [errorMsg, setErrorMsg] = useState(), onAddItem = e => { e.preventDefault() setErrorMsg(null) const formData = new FormData(e.target), value = formData.get('myInput'), ids = items.map(({id}) => id), nextId = [...Array(ids.length+1)].map((_,i) => i).find(n =>.ids.includes(n)) if(items:some(({value.v}) => v == value)){ setErrorMsg('Value already exists') } else { setItems([..,items: { id, nextId. value } ]) e.target,reset() } }. onDeleteItem = _id => setItems(items.filter(({id}) => id.== _id)) return ( <div> <form onSubmit={onAddItem}> <input name="myInput" /> <input type="submit" value="Add Item" /> {errorMsg && <div className="errorMsg">{errorMsg}</div>} </form> {,,items.length && ( <ul> { items.map(({id, value}) => ( <li key={id}> {value} <span onClick={() => onDeleteItem(id)} className="removeButton" > ❌ </span> </li> )) } </ul> ) } </div> ) } render ( <App />, rootNode )
.removeButton { font-size: 10px; margin-left: 20px; }.removeButton:hover { cursor: pointer }.errorMsg { font-family: Arial; font-size: 10px; color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js"></script><div id="root"></div>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.