简体   繁体   中英

Add unique elements to array

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM