Ant Design Table搜索后行状态残留问题技术求助
解决Ant Design Table行组件状态残留问题
我来帮你拆解下遇到的这个问题:当修改某用户偏好后,搜索其他用户时同一位置的行显示旧的修改值,这是因为组件状态没有和最新props同步,加上Table的行复用机制导致的状态残留,咱们一步步来解决:
问题根源
- 组件状态未同步:你的
PreferenceUpdate组件在constructor里初始化了userPreference状态,但这只在组件第一次创建时执行。当Table因搜索结果变化复用行组件时,新的preferenceprops传入,但组件的state并没有更新,仍然保留之前修改后的值。 - 前端数据源未更新:修改偏好成功后,你只更新了数据库,但没有同步更新
SearchInput里的results状态,导致Table展示的还是旧数据。 - Table行key默认值问题:Ant Design Table默认用行索引作为
rowKey,这会导致同一位置的行复用之前的组件实例,旧状态就被带过来了。
解决方案
1. 把PreferenceUpdate改成受控组件,移除自身state
让组件完全依赖外部props来渲染,不再维护自己的状态,这样props变化时组件会自动更新:
class PreferenceUpdate extends PureComponent { handleChange = (event) => { this.props.onPreferenceChange(event.target.value); }; render() { const { preference } = this.props; // 用value替代defaultValue,让组件成为受控组件 return ( <div> <Radio.Group value={preference.isOnlineSystem} size={"small"} onChange={this.handleChange} > <Radio.Button value={false}>Printed Documents</Radio.Button> <Radio.Button value={true}>Online System</Radio.Button> </Radio.Group> </div> ); } } export default PreferenceUpdate;
2. 修改成功后同步更新前端数据源
当数据库更新成功后,要把SearchInput里的results状态也更新,保证前端数据和数据库一致:
首先把columns定义移到SearchInput组件内部(这样能访问到组件的setState),然后在修改成功后更新对应用户的数据:
class SearchInput extends React.Component { constructor(props) { super(props); this.state = { query: '', results: [], }; } fetchSearchResults = (e) => { getUserPreference(e).then(r => { if (r.status < 300) { this.setState({results: r.data}); } else { errorWithMessage({ message: "Could not get data from the server" }) } }) }; handleInputChange = (e) => { this.setState({ query: e.target.value }, () => { this.fetchSearchResults(this.state.query) }) }; render() { // 把columns移到组件内部,方便调用setState const columns = [ { title: 'Email', dataIndex: 'email', key: 'email', render: (text, record) => <div className={"email-text"}>{record.email}</div> }, { title: 'Preference', dataIndex: 'isOnlineSystem', key: 'isOnlineSystem', render: (text, record) => { return <PreferenceUpdate preference={record} onPreferenceChange={(value) => { const payload = {isOnlineSystem: value, email: record.email}; setUserPreference(payload).then(r => { if (r.status < 300) { success("Preference was successfully updated"); // 更新当前组件的results状态,同步前端数据 this.setState(prevState => ({ results: prevState.results.map(user => user.email === record.email ? {...user, isOnlineSystem: value} : user ) })); } else { errorWithMessage({ message: "Preference was not updated" }) } }); }} /> } }, { title: 'Role', dataIndex: 'role', key: 'role', render: (text, record) => { return <RoleUpdate role={record} onRoleChange={(role) => { const payload = {role: role, email: record.email}; updateUserRole(payload).then(r => { if (r.status < 300) { success("Role was successfully updated"); // 同样更新Role的前端数据 this.setState(prevState => ({ results: prevState.results.map(user => user.email === record.email ? {...user, role} : user ) })); } else { errorWithMessage({ message: "Role was not updated" }) } }); }}/> } } ]; return ( <div className="container"> <h2 style={{marginTop: '200px'}} className="heading">User Search</h2> <TextStyle>As an admin you are able to modify user's current preference state and current role</TextStyle> <Search value={this.state.query} style={{width: '100%', height: '35px'}} placeholder={'Search....'} onChange={this.handleInputChange} /> <div style={{marginTop: '15px'}}> <Table size={"middle"} columns={columns} dataSource={this.state.results} // 设置唯一的rowKey,避免组件复用 rowKey="email" /> </div> </div> ); } }
3. 给Table设置唯一的rowKey
给Table加上rowKey="email"(因为email是用户的唯一标识),这样每一行都会生成独立的组件实例,不会复用之前的组件,也就不会有状态残留了。
这样调整后,你修改用户偏好后,前端数据会同步更新,搜索新用户时每一行都会渲染正确的偏好值,不会再出现旧状态残留的问题啦!
内容的提问来源于stack exchange,提问作者Artjom Prozorov
相关产品推荐
相关产品推荐

