I have an Array of objects in useState, I want to be able to move position up or down in the map loop.
const data = [
{id: 1, person: "John Doe"},
{id: 2, person: "Jane Doe"},
{id: 3, person: "Tom Bar"},
{id: 4, person: "Jim Qux"},
]
const [entries, setEntries] = useState(data)
I'm using this code I found online, it does move an object up if the the Array only contains two objects, if more than two it removes the rest.
const moveUp = (index) => {
if (index < 1 || index >= entries.length) {
return;
}
setEntries(
([entries[index - 1], entries[index]] = [
entries[index],
entries[index - 1],
])
);
};
JSX:
{entries.map((item, index) => (
<div key={item.id}>
<h4>{item.person}</h4>
<button onClick={() => moveUp(index)}>Move Up</button>
</div>
))}
CodePudding user response:
Don't pass the assignment directly to setEntries
. Instead, you can take the previous state, create a shallow copy, and then do the assignments with the copy.
const { useState } = React;
function App() {
const data = [
{ id: 1, person: "John Doe" },
{ id: 2, person: "Jane Doe" },
{ id: 3, person: "Tom Bar" },
{ id: 4, person: "Jim Qux" },
];
const [entries, setEntries] = useState(data);
const moveUp = (index) => {
if (index < 1 || index >= entries.length) return;
setEntries((entries) => {
entries = [...entries];
[entries[index - 1], entries[index]] = [
entries[index],
entries[index - 1],
];
return entries;
});
};
return (
<div>
{entries.map((item, index) => (
<div key={item.id}>
<h4>{item.person}</h4>
<button onClick={() => moveUp(index)}>Move Up</button>
</div>
))}
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.0/umd/react-dom.production.min.js"></script>