Estoy practicando reaccionar y tengo esta tarea para construir una interfaz donde un botón puede agregar elementos, otro botón puede eliminar elementos y otros dos botones pueden mover cada elemento hacia arriba o hacia abajo paso a paso de esta manera:
He podido hacer que los botones agreguen y eliminen elementos, pero cambiar las posiciones de los elementos me ha dado dolor de cabeza. A continuación se muestra mi código:
const [inputList, setInputList] = useState([{ inputBox: '' }]); const handleInputChange = (e, index) => { const { name, value } = e.target; const list = [...inputList]; list[index][name] = value; setInputList(list); }; const handleRemoveClick = (index) => { const list = [...inputList]; list.splice(index, 1); setInputList(list); }; const handleAddClick = () => { setInputList([...inputList, { inputBox: '' }]); }; const upPosition = () => { console.log('up'); }; const downPosition = () => { console.log('down'); }; return ( <div> <h3>Add Elements</h3> <button onClick={handleAddClick}>+</button> {inputList.map((x, i) => { return ( <div className='box inputBox' key={i}> <input name='inputBox' value={x.inputBox} onChange={(e) => handleInputChange(e, i)} /> <button onClick={() => upPosition()}> <i className='fas fa-long-arrow-alt-up'></i> </button> <button onClick={() => downPosition()}> <i className='fas fa-long-arrow-alt-down'></i> </button> <button className='mr10' onClick={() => handleRemoveClick(i)}> <i className='fas fa-times'></i> </button> </div> ); })} </div> );
Puede hacer uso de empalme aquí
Además del cambio, también debe manejar los 2 casos, donde no puede subir si el índice es 0
y no puede bajar si el índice es inputList.length - 1
NOTA: Para manejar ambos casos, he deshabilitado los botones porque eso sería más significativo para que el usuario final sepa que este botón está deshabilitado para que no pueda subir o bajar.
Demo en vivo
const upPosition = ( index ) => { const copy = { ...inputList[index] }; setInputList( ( oldState ) => { const newState = oldState.filter( ( o, i ) => i !== index ); newState.splice( index - 1, 0, copy ); return newState; } ) }; const downPosition = (index) => { const copy = { ...inputList[index] }; setInputList( ( oldState ) => { const newState = oldState.filter( ( o, i ) => i !== index ); newState.splice( index + 1, 0, copy ); return newState; } ) };
Debe usar el método de splice
que también puede hacer inserciones
const upPosition = (indexToMove) => { if (indexToMove === 0) return; const list = [...inputList]; const itemToMove = list.splice(indexToMove, 1)[0]; list.splice(indexToMove-1, 0, itemToMove) setInputList(list) }; const downPosition = (indexToMove) => { if (indexToMove === inputList.length - 1) return; const list = [...inputList]; const itemToMove = list.splice(indexToMove, 1)[0]; list.splice(indexToMove+1, 0, itemToMove) setInputList(list) };
Creo que se puede lograr con la desestructuración:
const [inputList, setInputList] = useState([{ inputBox: '' }]); const handleInputChange = (e, index) => { const { name, value } = e.target; const list = [...inputList]; list[index][name] = value; setInputList(list); }; const handleRemoveClick = (index) => { const list = [...inputList]; list.splice(index, 1); setInputList(list); }; const handleAddClick = () => { setInputList([...inputList, { inputBox: '' }]); }; const upPosition = (i) => { if (i > 0) { const temp = [...inputList]; [temp[i], temp[i - 1]] = [temp[i - 1], temp[i]]; setInputList(temp); } }; const downPosition = (i) => { if (i < inputList.length - 1) { const temp = [...inputList]; [temp[i], temp[i + 1]] = [temp[i + 1], temp[i]]; setInputList(temp); } }; return ( <div> <h3>Add Elements</h3> <button onClick={handleAddClick}>+</button> {inputList.map((x, i) => { return ( <div className="box inputBox" key={i}> <input name="inputBox" value={x.inputBox} onChange={(e) => handleInputChange(e, i)} /> <button onClick={(e) => upPosition(i)}> <i className="fas fa-long-arrow-alt-up"></i> </button> <button onClick={() => downPosition(i)}> <i className="fas fa-long-arrow-alt-down"></i> </button> <button className="mr10" onClick={() => handleRemoveClick(i)}> <i className="fas fa-times"></i> </button> </div> ); })} </div> );