React结合Antd实现动态标签页时重复新增、关闭全标签问题排查
问题修复方案
根因分析
新增标签重复问题
- React17 严格模式下 setState 的更新函数会执行两次用于副作用检测,你的 add 方法中直接对原 state 里的 panes 数组执行 push 操作,属于直接修改 state 的副作用操作,两次执行就会插入两个相同标签。
- 浅拷贝 state 后 panes 数组引用未变,修改时直接污染了原 state。
- 箭头函数定义的 add 方法在 constructor 中重复绑定 this,存在重复触发风险。
- 未使用你预先定义的 newTabIndex 变量生成唯一 key,用 activeKey+1 的逻辑存在 key 重复隐患。
关闭标签清空+报错问题
- remove 方法中错误直接遍历 state 对象(newState 是包含 activeKey、panes 属性的对象,不存在 forEach 方法),调用时报错导致后续逻辑异常,最终标签全部被清空。
修复后代码
import React from 'react'; import { Tabs, Button } from 'antd'; import 'antd/dist/antd.css'; const { TabPane } = Tabs; class App extends React.Component { constructor(props) { super(props); this.newTabIndex = 0; const panes = []; this.state = { activeKey: '', // 初始无标签,设为空避免不匹配 panes, }; this.onChange = this.onChange.bind(this); this.onEdit = this.onEdit.bind(this); } onChange(activeKey) { this.setState({ activeKey }); }; onEdit(targetKey, action){ this[action](targetKey); }; add = (targetKey) => { this.setState(prevState => { // 生成新的panes数组,不修改原数组 const newPane = { title: 'Tab ' + targetKey, content: 'Content of tab pane ' + targetKey, key: `tab-${this.newTabIndex++}` // 用自增变量生成唯一key } const newPanes = [...prevState.panes, newPane]; return { panes: newPanes, activeKey: newPane.key // 新增后自动跳转到新标签 } }); }; remove = (targetKey) => { this.setState(prevState => { let lastIndex; // 遍历panes数组,不是state对象 prevState.panes.forEach((pane, i) => { if (pane.key === targetKey) { lastIndex = i - 1; } }); const panes = prevState.panes.filter(pane => pane.key !== targetKey); let activeKey = prevState.activeKey; if (panes.length && activeKey === targetKey) { if (lastIndex >= 0) { activeKey = panes[lastIndex].key; } else { activeKey = panes[0].key; } } else if (!panes.length) { activeKey = ''; // 标签全部删除后重置activeKey } return { panes, activeKey }; }); }; render() { return ( <div className="tab-section"> <div style={{ marginBottom: 16 }}> { ['1', '2', '3'].map(item => <Button key={item} onClick={() => this.add(item)}>ADD Tab-{item}</Button> ) } </div> <Tabs hideAdd onChange={this.onChange} activeKey={this.state.activeKey} type="editable-card" onEdit={this.onEdit} > {this.state.panes.map(pane => ( <TabPane tab={pane.title} key={pane.key}> {pane.content} </TabPane> ))} </Tabs> </div> ); } } export default App;
内容的提问来源于stack exchange,提问作者Thomas Deepak Konreddy
相关产品推荐
相关产品推荐

