我有一个映射的申请人列表,每个申请人都包含一个 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
对象突变。
我认为发生的步骤是:
DashboardRowDynamic
呈现表数据数组并呈现ProfileFinalStatus
组件。ProfileFinalStatus
通过调用setDropdownData(utils.getDropdownData('complianceStatus', applicantSelect));
来填充其dropdownData
状态数组。getDropdownData
data.dropdownData[type]
作为dropdownData
传递给mergeArray
,并返回mergeArray
的返回值。mergeArray
调用disableComplianceStatus
并通过dropdownData
并返回dropdownData
。disableComplianceStatus
直接改变dropdownData
对象,设置disabled
属性。
当这种情况在循环中发生时,每次迭代都会改变这个相同的对象,因为它仍然是对存储在从data.js
文件导出的对象中的原始对象的引用。每个迭代项都会改变引用的对象,并且正在改变所有先前元素具有的对象引用。
溶液
在此流程中的某个时刻,您只需要浅拷贝dropdownData
对象,以便每个映射元素都有自己的副本来改变。这个IMO的一个好地方是disableComplianceStatus
实用程序。它应该复制、设置属性并返回新对象,而不是改变传递的对象。 然后,mergeArray
应返回该新对象,而不是传递的dropdownData
对象。
我向您提交以下更改
-
mergeArray
从它调用的实用程序返回结果。const mergeArray = (dropDownData, type, data) => { if (type === 'actionList') { return mergeArrayActionListHelper(dropDownData, data); } if (type === 'complianceStatus') { return disableComplianceStatus(dropDownData, data); } return dropDownData; }
-
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],
}));
}