《问题总结》分类列表拖拽排序后,接着修改下拉选项值,分类列表排序顺序重新回到原始状态
问题描述
在做企业frontpagesetting的时候,有个分类列表,需要支持对分类进行排序,但是在对分类排序之后,然后修改下拉选项值,排序列表重新回到了原始状态
问题分析
在组件生命周期getDerivedStateFromProps方法中,比对props, state中的list数据,因为displayType是可变的,所以会判断 R.symmetricDifference不为空,从而导致重新赋值state的list值,造成排序被还原
解决方法
思路:
知道上面是因为排序之后在修改下拉选项值之后,导致的列表顺序还原,displayType是可变的。基于这个原因,不使用list来判断,而是使用itemIds单个的id数组,这样不管顺序怎么排列,和displayType的值怎么修改都不会造成顺序还原。
代码实现:
1、生命周期函数getDerivedStateFromProps中比对id数组,并赋值给state的itemIds
static getDerivedStateFromProps(props, state) {
if (
!R.isEmpty(
R.symmetricDifference(
R.pluck(props.draggableId, props.dataSource),
state.itemIds
)
)
) {
return {
itemIds: R.pluck(props.draggableId, props.dataSource)
}
}
return null
}
2、渲染数据列表时候 ,通过遍历itemIds,根据id从dataSource中获取并显示相关filed字段
{this.state.itemIds.map((id, index) => {
const item = R.find(R.propEq(draggableId, id), dataSource)
return (
<Draggable
draggableId={item[draggableId]}
index={index}
key={item[draggableId]}
>
{(provided2, snapshot2) => (
<div
className={styles.dndRow}
ref={provided2.innerRef}
{...provided2.draggableProps}
{...provided2.dragHandleProps}
style={{
...this.getDraggableStyle(
snapshot2.isDragging,
provided2.draggableProps.style
),
...this.getColumnsStyle()
}}
>
<div>
<img src={dragHandleIcon} />
</div>
{this.renderDraggableContent(item)}
</div>
)}
</Draggable>
)
})}
3、监听排序函数,将排序后的itemIds传递到父组件中
onDragEnd = result => {
const { destination, source } = result
const { onOrderChange } = this.props
// dropped outside the list
if (R.isNil(destination)) return
// dropped in same position
if (
R.allPass([R.eqProps('droppableId'), R.eqProps('index')])(
destination,
source
)
) {
return
}
this.setState(
prevState => ({
itemIds: this.reorder(
prevState.itemIds,
source.index,
destination.index
)
}),
() => {
onOrderChange(this.state.itemIds)
}
)
}
reorder = (list, startIndex, endIndex) => {
const newOrder = R.insert(
endIndex,
list[startIndex],
R.remove(startIndex, 1, list)
)
return newOrder
}
4、父组件监听到排序函数重新表单赋值
handleOrderChange = newOrder => {
this.props.form.setFieldsValue({
order: newOrder
})
}
<Form.Item>
<DragAndDropTable
draggableId="corporateCategoryNo"
dataSource={corporateFrontpageCategoryList.toJS()}
columns={getCorporateCategoryColumns(
corporateFrontpageCategoryList,
form
)}
onOrderChange={this.handleOrderChange}
/>
</Form.Item>
{getFieldDecorator('order', {
initialValue: corporateFrontpageCategoryList
.map(corpCat => corpCat.get('corporateCategoryNo'))
.toArray()
})(<React.Fragment />)}
5、selector中处理接口返回的controlSetting数据,在corporateCategoryList中添加列表所需要的name字段
export const getCorporateFrontpageCategoryList = createSelector(
getCorporateCategoryList,
controlSettingSelector,
(corporateCategoryList, controlSetting) => {
if (R.isNil(corporateCategoryList) || R.isNil(controlSetting)) {
return List()
}
return controlSetting
.get('corporateCategoryList')
.map(frontpageCorpCat =>
frontpageCorpCat.set(
'name',
corporateCategoryList
.find(
(corpCat, key, iter) =>
corpCat.get('corporateCategoryNo') ===
frontpageCorpCat.get('corporateCategoryNo')
)
.get('name')
)
)
}
)
6、在getCorporateCategoryColumns中使用displayType.${corporateCategoryNo}.displayType形式给select赋值
数据格式 displayType: {CORPCATE10034: {…}, CORPCATE10091: {…}, CORPCATE10093
{
title: i18n.t('corporateFrontpageSetting.label.imgStyle'),
dataIndex: 'corporateCategory.displayType',
key: 'displayType',
render: ({ corporateCategoryNo, displayType }: Object, index: number) => {
return getFieldDecorator(
`displayType.${corporateCategoryNo}.displayType`,
{
initialValue: displayType
}
)(
<Select style={{ width: 100 }}>
<Select.Option value={0}>
{i18n.t('corporateFrontpageSetting.label.smallImgStyle')}
</Select.Option>
<Select.Option value={1}>
{i18n.t('corporateFrontpageSetting.label.bigImgStyle')}
</Select.Option>
</Select>
)
}
},
//删除列表行数据
{
title: i18n.t('corporateFrontpageSetting.label.action'),
dataIndex: 'corporateCategory.action',
width: 100,
key: 'action',
render: (record: Object) => {
const updatedFrontpageCorporateCategoryList = corporateCategoryList.filterNot(
item => item.get('corporateCategoryNo') === record.corporateCategoryNo
)
return (
<DelBtn
updatedFrontpageCorporateCategoryList={
updatedFrontpageCorporateCategoryList
}
/>
)
}
}
7、最后请求保存接口的时候对数据做处理
解构formValues中除了order和displayType的数据,处理并组装corporateCategoryList数据,最后拼装并返回接口请求所需格式
corporateHome: {articleIds: Array(4), displayCorporateCategory: "CORPCATE10077"}
corporateCategoryList: (6) [{…}, {…}, {…}, {…}, {…}, {…}]
patchFormValues = formValues => {
return {
...R.omit(['order', 'displayType'])(formValues),
corporateCategoryList: R.map(
corporateCategoryNo => ({
corporateCategoryNo,
displayType: R.path(
['displayType', corporateCategoryNo, 'displayType'],
formValues
)
}),
R.path(['order'])(formValues)
)
}
}
2020.3.4更新
测试的时候发现了个bug,在排序后接着删除一天分类数据,再保存页面数据失败。
- 原因
排序后的order和删除后的order数据不一致导致 - 解决办法
删除成功后重新设置order的数据
const handleConfirm = e => {
message.loading({
content: t('message.deleting'),
key: 'API_REQUEST'
})
dispatch(
updateControlSettingRequest({
controlSetting: {
corporateCategoryList: updatedFrontpageCorporateCategoryList.toJS()
}
})
).then(() => {
setFieldsValue({
order: getFieldValue('order').filter(item => {
return item !== corporateCategoryNo
})
})
message.success({
content: t('message.deleteSuccess'),
key: 'API_REQUEST'
})
})
}
继续2020.3.4更新
上个问题的解决方式,有点粗暴,导致后续出现新的问题。
对分类排序后(未保存),接着添加新的分类,添加成功,但页面不能正常展示出来,需要刷新页面,原因还是和上面问题是同一个问题,添加成功后返回新数据没有动态更新form中order的值
解决办法是:
antd为我们提供了一个resetFields方法,这个方法可以重置form属性的initialValues初始值,所以只需要在添加分类成功后调用下这个resetFields方法即可,代码如下。同理解决上个问题,只要在删除成功后resetFields方法。
const handleConfirm = e => {
message.loading({
content: t('message.deleting'),
key: 'API_REQUEST'
})
dispatch(
updateControlSettingRequest({
controlSetting: {
corporateCategoryList: updatedFrontpageCorporateCategoryList.toJS()
}
})
).then(() => {
resetFields(['order'])
message.success({
content: t('message.deleteSuccess'),
key: 'API_REQUEST'
})
})
}
解决参考
文章出处:https://www.cnblogs.com/fozero
声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。