Best practice
To be honest, you shouldn't mutate state data directly. You should clone then do your task like this
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
Why can't I directly modify a component's state, really?
The previous state
will be polluted with your mutation. Due to which, the shallow compare and merge of two states will be
disturbed or won't happen, because you'll have only one state now.
This will disrupt all the React's Lifecycle Methods.
Your problem & solution
- In case that you use the input
readOnly
, you should change from defaultValue
to value
then your code work well.
<input type="text" value={student.score} readOnly />
class App extends React.Component {
constructor() {
super();
this.state = {
students: [
{ name: "A", score: 10 },
{ name: "B", score: 20 },
{ name: "C", score: 30 }
]
};
}
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
render() {
return (
<div>
{this.state.students.map((student, index) => {
return (
<div key={index}>
<b>{student.name}</b> -{" "}
<input type="text" value={student.score} readOnly />
<button onClick={this.onDelete.bind(this, index)}>delete</button>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
- Otherwise, you should provide the unique
key
. If student.name
is not unique, you can randomly GUID
like this.
const getGUID = () => "id" + Math.random().toString(16).slice(2);
> <div key={getGUID()}>
const getGUID = () => "id" + Math.random().toString(16).slice(2);
class App extends React.Component {
constructor() {
super();
this.state = {
students: [
{ name: "A", score: 10 },
{ name: "B", score: 20 },
{ name: "C", score: 30 }
]
};
}
onDelete(index) {
const newStudents = [...this.state.students];
newStudents.splice(index, 1);
this.setState({ students: newStudents });
}
render() {
return (
<div>
{this.state.students.map((student, index) => {
return (
<div key={getGUID()}>
<b>{student.name}</b> -{" "}
<input type="text" defaultValue={student.score} />
<button onClick={this.onDelete.bind(this, index)}>delete</button>
</div>
);
})}
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
However, in this case, Unstable keys will cause harmful performance because component instances - Virtual DOM
& DOM node - actual DOM
will always unnecessary recreated.
In short, depends on your data and behavior, you can choose the correct way to complete it.