I'm using Antd Modal to display order information by passing props to TableDetail Component. The thing is when I try to remove the items in the order I use setState and the modal won't update its data.
https://codesandbox.io/s/antd-reproduction-template-forked-vu3ez A simple version of reproduction is provided above.
enter image description here After I click on the remove button the items remain unchanged but when I close and open the modal it will update. enter image description here
What should I do to make it change? I tried forceUpdate() but it won't work.
Here is the TableDetail component.
export default class TableDetail extends Component {
constructor(props) {
super(props);
this.state = {
tableOrder: props.tableOrder,
column: []
};
}
tableInitializer = () => {
const column = [
{
title: "name",
render: (item) => {
return <span>{item.name}</span>;
}
},
{
title: "price",
render: (item) => {
return item.price;
}
},
{
title: "amount",
render: (item) => {
return <span>{item.amount}</span>;
}
},
{
title: "removeButton",
render: (item) => {
return (
<Button
type="link"
style={{ color: "red" }}
onClick={() => this.props.removeItem(item)}
>
Remove
</Button>
);
}
}
];
this.setState({
column
});
};
UNSAFE_componentWillMount() {
this.tableInitializer();
}
render() {
return (
<Modal
visible={true}
title={
<span style={{ fontSize: "1.5rem", fontWeight: "bold" }}>
Table: {this.state.tableName}
</span>
}
cancelText="Cancel"
okText="OK"
onCancel={this.props.hideModal}
>
<Table
columns={this.state.column}
dataSource={this.state.tableOrder}
rowKey="name"
/>
</Modal>
);
}
}
TableDetail.propTypes = {
tableOrder: PropTypes.array.isRequired,
tableName: PropTypes.string.isRequired,
hideModal: PropTypes.func.isRequired,
removeItem: PropTypes.func.isRequired
};
The issue in your code is in removeItem
. You are trying to mutate tableOrder. According to react docs :
Never mutate this.state directly, as calling setState() afterwards may replace the mutation you made. Treat this.state as if it were immutable
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
So that is why it is kind of asynchronous and you can't see your updated changes. You need to do this:
removeItem = (item) => {
const { tableOrder } = this.state;
const newTable = [...tableOrder]; <- Create new variable and update variable
for (let i = 0; i < newTable.length; i++) {
if (item.name === newTable[i].name) {
console.log("Got it! " + newTable[i].name);
newTable.splice(i, 1);
console.log("new table: ", tableOrder);
break;
}
}
this.setState({
tableOrder: newTable <- update here
});
};
You dont need to actually modify array you can simply do this also:
this.setState(
{
tableOrder: this.state.tableOrder.filter(data => !(data.name===item.name))
}
)
//filter creates new array
Here is demo: https://codesandbox.io/s/antd-reproduction-template-forked-j4bfl?file=/tables.js
You can use the filter
method in your removeItem
function
removeItem = (item) => {
const filtered = this.state.tableOrder.filter(
(order) => item.name !== order.name
);
console.log(item, filtered);
this.setState({
tableOrder: filtered
});
};
and one more thing you should avoid assigning your props to state like
this.state = {
tableOrder: props.tableOrder,
};
instead of assigning to state directly use that as props like
<Table
dataSource={this.props.tableOrder}
/>
In most cases, this is an antipattern. Don't “copy props into state.” It creates a second source of truth for your data, which usually leads to bugs. One source of truth is best.
Improved code Live demo
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.