辅助函数覆盖 React 中映射列表中的先前值



我有一个映射的申请人列表,每个申请人都包含一个 finalStatus 属性。此映射列表使用自定义下拉列表呈现组件,并将申请人作为道具。

我有一个带有下拉对象的数据文件,我将其拉入组件以呈现下拉列表。

这些中的每一个都有一个禁用的属性 true 或 false,最初设置为 false,如下所示......

complianceStatus: [
{id: 1,  value: 'None', disabled: false },
{id: 2,  value: 'Provisionally', disabled: false},
{id: 3,  value: 'Fully', disabled: false },
],

然后,当组件挂载时,我运行 useEffect 来获取下拉数据并对其执行帮助程序函数,以便根据申请人对象的值确定禁用是否应为真或假。然后,我将此对象设置为 state 以呈现下拉列表。

这是使用效果

useEffect(() => {
setDropdownData(utils.getDropdownData('complianceStatus', applicant));
}, [applicant]);

供参考,我的实用程序功能在这里

export const getDropdownData = (type, applicant) => {
const optionData = mergeArray(data.dropdownData[type], type, applicant);
return optionData;
}

const mergeArray = (dropDownData, type, data) => {
if (type === 'actionList') {
mergeArrayActionListHelper(dropDownData, data);
}
if (type === 'complianceStatus') {
disableComplianceStatus(dropDownData, data);
}
return dropDownData;
}

export const disableComplianceStatus = (dropdownData, applicant) => {

switch(applicant.finalStatus) {
case 'fully_compliant':
dropdownData[0].disabled = true;
dropdownData[1].disabled = true;
dropdownData[2].disabled = true;
return;
case 'partially_compliant':
dropdownData[0].disabled = true;
dropdownData[1].disabled = true;
dropdownData[2].disabled = false;
return;
default:
dropdownData[0].disabled = true;
dropdownData[1].disabled = false;
dropdownData[2].disabled = false;
return;

}
}

我的下拉列表列表正在渲染,但有一个奇怪的怪癖。

问题是,列表中的最后一个申请人似乎覆盖了所有先前申请人的禁用属性。

知道为什么会发生这种情况吗?

编辑以获取有关申请人的更多信息

申请人是一个大对象几个组件。它适用于表格样式仪表板,其中每个申请人都有一行。

它首先传递给没有设置状态的 DashboardRow 组件。

return (
<div className='dashboard-row'>
{
staticDash ? (
<DashboardRowStatic applicant={applicant}/>
) : (
<DashboardRowDynamic 
applicant={applicant} 

/>
)
}
</div>
)

然后,这将在行上呈现实际项,组件如下所示

const DashboardRowDynamic = ({applicant, applicantNumber, applicantLength}) => {
const dynamicTableData = useSelector(state => state.dashboard.dynamicTableData);
return (
dynamicTableData && dynamicTableData.length > 0 && 
<div className='dashboard-row-dynamic'>
{
dynamicTableData[1].values.map(value => {
if (value === 'finalStatus') {
return (
<div key={value} className='col-md center'>
<ProfileFinalStatus 
applicantFromDash={applicant} 
applicantNumber={applicantNumber} 
applicantLength={applicantLength} 
/>
</div>
)
} 

else if (value === 'suspendedMessage') {
return (
<div key={value} className='col-md'>
<TooltipLg title={applicant[value]}>
<p className='orka-semi-p tooltip'>{applicant[value]}</p>
</TooltipLg>
</div>
)

} else {
return (
<div key={value} className='col-md'>
<p className='orka-semi-p'>{applicant[value]}</p>
</div>
)
} 
})
}
</div>
)
}

然后作为参考,这是整个最终状态组件

const ProfileFinalStatus = ({applicantFromDash, applicantNumber = 0, applicantLength = 20}) => {
const applicant = useSelector(state => state.profile.applicant);
const dispatch = useDispatch();
const [dropdownData, setDropdownData] = useState([]);
const [defaultData, setDefaultData] = useState(null);
const [localApplicant, setLocalApplicant] = useState(null);

useEffect(() => {
const applicantSelect = applicantFromDash ? applicantFromDash : applicant;
setLocalApplicant(applicantSelect);
setDropdownData(utils.getDropdownData('complianceStatus', applicantSelect));
}, [applicant, applicantFromDash]);
useEffect(() => {
if (localApplicant) {
const data = dropdownData.filter(item => {
return item.dbValue === localApplicant.finalStatus;
});
getIcon(data);           
setDefaultData(data[0]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(dropdownData), JSON.stringify(localApplicant)]);

const getIcon = (data) => {
switch(data[0].dbValue) {
case 'partially_compliant':
data[0].icon = partially;
return;
case 'fully_compliant':
data[0].icon = fully;
return;
default:
data[0].icon = none;
return;
}
}

const getDropdownVal = (val) => {
const payload = {
finalStatus: val.dbValue
}
apiApplicant.updateApplicant(localApplicant.workerUuid, payload)
.then(res => {
const data = dropdownData.filter(item => {
return item.dbValue === payload.finalStatus;
});
localApplicant.finalStatus = val.dbValue;
setDropdownData(utils.getDropdownData('complianceStatus', localApplicant));

setDefaultData(data[0]);
if (applicantFromDash) {
dispatch(refetchApplicants());
}
dispatch(setAlert({
type: 'success',
message: 'Successfully updated compliance status',
isVisible: true
}));
})
.catch(err => {
dispatch(setAlert({
type: 'error',
message: 'Error updating face to face status',
isVisible: true
}));
})
}
const getPosition = () => {
let position;
// applicantLength = 2;
// if (applicantLength === 2) {
//     position = 'top-center';
// } else {
position = applicantNumber > 16 ? 'top-center' : 'bottom-center';
// }
// console.log(applicantLength)
// console.log(position)
return position;
}
return (
<div>
{
defaultData &&
(
<Dropdown 
type="complianceStatus" 
dropdownData={dropdownData}
defaultData={defaultData} 
getDropdownVal={getDropdownVal} 
width="160"
height='24'
mobileResponsive={false}
position={getPosition()}
/>
)
}


</div>
)
}
export default ProfileFinalStatus;

编辑 2 下拉列表数据位于文件数据中.js

export const dropdownData = {
searchBy: [
{id: 1,  value: 'First Name', dbValue: 'name', class: "dropdown-grey"},
{id: 2,  value: 'Surname', dbValue: 'surname', class: "dropdown-grey"},
{id: 3,  value: 'Email', dbValue: 'email', class: "dropdown-grey"},
{id: 4,  value: 'NI Number', dbValue: 'nationalInsuranceNumber', class: "dropdown-grey"}
],
sortBy: [
{id: 1,  value: 'Urgent', dbValue: 'urgent', sortAsc: false, class: "dropdown-grey"},
{id: 2,  value: 'Name', dbValue: 'name', sortAsc: false, class: "dropdown-grey"},
{id: 3,  value: 'Email', dbValue: 'email', sortAsc: false, class: "dropdown-grey"},
{id: 4,  value: 'Created Date', dbValue: 'created_at', sortAsc: false, class: "dropdown-grey"}
],
submissionStatus: [
{id: 1,  value: 'Pending', dbValue: 'pending', class: "dropdown-grey"},
{id: 2,  value: 'Accepted', dbValue: 'accepted', class: "dropdown-grey"},
{id: 3,  value: 'Rejected', dbValue: 'rejected', class: "dropdown-grey"},
{id: 4,  value: 'Unsuccessful', dbValue: 'unsuccessful', class: "dropdown-grey"}
],
complianceStatus: [
{id: 1,  value: 'None', dbValue: 'not_compliant', class: "dropdown-grey", disabled: false },
{id: 2,  value: 'Provisionally', dbValue: 'partially_compliant', class: "dropdown-yellow", disabled: false},
{id: 3,  value: 'Fully', dbValue: 'fully_compliant', class: "dropdown-green", disabled: false },
],
actionList: [
{id: 1,  value: 'Suspended', openModal: true, isSuspended: false },
{id: 2,  value: 'Mark Urgent', openModal: false, isUrgent: false },
{id: 3,  value: 'Edit User', openModal: true },
{id: 4,  value: 'CV Online', openModal: false },
{id: 5,  value: 'Identity Check', openModal: true },
],
employmentTypes: [
{id: 1,  dbValue: 'employed', value: 'Employed', fullView: true, class: 'blue-outline' },
{id: 2,  dbValue: 'self-employed', value: 'Self Employed', fullView: false, class: 'blue-outline'   },
{id: 3,  dbValue: 'studying', value: 'Studying', fullView: true, class: 'blue-outline'   },
{id: 4,  dbValue: 'carer', value: 'Carer', fullView: false, class: 'blue-outline'  },
{id: 5,  dbValue: 'redundant', value: 'Redundant', fullView: true, class: 'blue-outline'  },
{id: 6,  dbValue: 'sick', value: 'Sick', fullView: false, class: 'blue-outline'  },
{id: 7,  dbValue: 'travelling', value: 'Travelling', fullView: false, class: 'blue-outline'  },
{id: 8,  dbValue: 'volunteering', value: 'Volunteering', fullView: true, class: 'blue-outline'  },
{id: 9,  dbValue: 'unemployed-claiming', value: 'Unemployed Claiming', fullView: false, class: 'blue-outline'  },
{id: 10,  dbValue: 'unemployed-not-claiming', value: 'Unemployed Not Claiming', fullView: false, class: 'blue-outline'  },
],
faceToFaceActions: [
{id: 1, value: 'Pending', dbValue: 'pending', class: "dropdown-grey"},
{id: 2, value: 'Approve', dbValue: 'passed', class: "dropdown-grey"},
{id: 3, value: 'Reject', dbValue: 'failed', class: "dropdown-grey"}
]
}

然后有一个导入数据的实用程序函数文件

import * as data from './data.js';

您可以看到上面的实用程序函数。

然后在最终状态组件 utils 中像这样导入

import * as utils from '../../utils/utilsFunctions';

然后在 ProfileFinalStatus 组件中调用它,如上面的代码片段所示。

问题

我相信问题是disableComplianceStatus实用程序中dropdownData对象突变。

我认为发生的步骤是:

  1. DashboardRowDynamic呈现表数据数组并呈现ProfileFinalStatus组件。
  2. ProfileFinalStatus通过调用setDropdownData(utils.getDropdownData('complianceStatus', applicantSelect));来填充其dropdownData状态数组。
  3. getDropdownDatadata.dropdownData[type]作为dropdownData传递给mergeArray,并返回mergeArray的返回值。
  4. mergeArray调用disableComplianceStatus并通过dropdownData并返回dropdownData
  5. disableComplianceStatus直接改变dropdownData对象,设置disabled属性。

当这种情况在循环中发生时,每次迭代都会改变这个相同的对象,因为它仍然是对存储在从data.js文件导出的对象中的原始对象的引用。每个迭代项都会改变引用的对象,并且正在改变所有先前元素具有的对象引用。

溶液

在此流程中的某个时刻,您只需要浅拷贝dropdownData对象,以便每个映射元素都有自己的副本来改变。这个IMO的一个好地方是disableComplianceStatus实用程序。它应该复制、设置属性并返回新对象,而不是改变传递的对象。 然后,mergeArray应返回新对象,而不是传递的dropdownData对象。

我向您提交以下更改

  1. mergeArray从它调用的实用程序返回结果。

    const mergeArray = (dropDownData, type, data) => {
    if (type === 'actionList') {
    return mergeArrayActionListHelper(dropDownData, data);
    }
    if (type === 'complianceStatus') {
    return disableComplianceStatus(dropDownData, data);
    }
    return dropDownData;
    }
    
  2. disableComplianceStatus浅表复制dropdownData对象,然后更新属性,返回新的对象引用。这些需要在您要更新属性的每个级别完成,因此这也包括数组元素。

注意:您需要对实用程序应用类似的修复程序mergeArrayActionListHelper

export const disableComplianceStatus = (dropdownData, applicant) => {
let disabled = [];
switch(applicant.finalStatus) {
case 'fully_compliant':
disabled = [true, true, true];
break;
case 'partially_compliant':
disabled = [true, true, false];
break;
default:
disabled = [true, false, false];
break;
}
// return new mapped array with copies of all elements.
return dropdownData.map((el, i) => ({
...el,
disabled: !!disabled[i],
}));
}

相关内容

  • 没有找到相关文章

最新更新