Reputation: 3
I have a react component and I use useState to create values like this
const [value, setValue] = useState([
{ id: 0, name: "rafi" },
{ id: 1, name: "fii" },
]);
and I created a function inside the react component to rename array and delete array
function arrayObjectIndexOf(myArray, searchTerm, property) {
for (var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i][property] === searchTerm) return i;
}
return -1;
}
const renameValue = (id, name) => {
let index = arrayObjectIndexOf(value, id, "id");
let newValue= value;
neValue[index]["name"] = name;
setValue(newValue);
};
const deleteValue= (id) => {
let newValue= value.filter((list) => list.id !== id);
setValue(newValue);
};
and I render the component like this
<>
<h1>LIST</h1>
{value.map((list) => {
return (
<div key={list.id}>
<h1>{list.name}</h1>
<button type="button" onClick={() => deleteValue(list.id)}>
Remove
</button>
<button
type="button"
onClick={() => renameValue(list.id, "raa")}
>
Rename
</button>
</div>
);
})}
</>
In the React component, the rename button does not work (the name in the list has not changed), but when I press the rename button of the two buttons, and continue by pressing the delete button, the name in the list changes.
Is there someone who can help me on this problem. To make the rename button work properly. ask for suggestions on how to properly render components in React.
in peace. thx.
Upvotes: 0
Views: 80
Reputation: 50674
You're mutating your original state. As a result, when you return the same value for your state, react won't re-render your component. Updating the DOM can be an expensive operation, so React tries to minimize the amount of times it is updated. If your old state is equal (===
) to your new state, then react will skip the rendering.
const currState = [{}, {}, {}];
const newState = currState; // this does NOT create a copy, it just points newState to the same array in memory as currState
currState[0] = 0; // change value (mutate original `myState`)
console.log(currState === newState); // true (as exactly the same array in memory)
Instead, keep your changes immutable (ie: don't mutate your value
state directly). You can do this by creating a new array with modified object values. The below code will map through your value
array, which will create a new array of values, if the current object's id matches the provided id passed into your function call, then you can return a modified object with the name overwritten to be the name passed through into your function:
const renameValue = (id, name) => {
setValue(oldValue => oldValue.map(
obj => obj.id === id ? {...obj, name} : obj
));
};
See working example:
const {useState} = React;
const App = () => {
const [value, setValue] = useState([
{ id: 0, name: "rafi" },
{ id: 1, name: "fii" },
]);
const renameValue = (id, name) => {
setValue(oldValue => oldValue.map(
obj => obj.id === id ? {...obj, name} : obj
));
};
const deleteValue= (id) => {
let newValue= value.filter((list) => list.id !== id);
setValue(newValue);
};
return <React.Fragment>
<h1>LIST</h1>
{value.map((list) => {
return (
<div key={list.id}>
<h1>{list.name}</h1>
<button type="button" onClick={() => deleteValue(list.id)}>
Remove
</button>
<button
type="button"
onClick={() => renameValue(list.id, "raa")}
>
Rename
</button>
</div>
);
})}
</React.Fragment>
}
ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
Upvotes: 1