У меня есть список элементов управления, которые отправляются бэкэндом. Иногда необходимо обновить параметры раскрывающегося списка.
Я думал, что это сработает. Однако memoizedControls
не перерисовывается.
Я считаю, что это должно работать так:
handleFieldsChange()
сработает.setTechSpec('')
устанавливает techSpec
на ''usePerson
, потому что он имеет techSpec
в своем массиве зависимостейmemoizedControls
запускается, потому что он имеет personList
в своем массиве зависимостейupdateControlOptions()
обновляет параметры controls
Однако пользовательский интерфейс не перерисовывался, и новые параметры personList
не перерисовывались.
const [techSpec, setTechSpec] = useState('1')
const [personList, isLoadingPersonList] = usePerson(techSpec)
const handleFieldsChange = (changedValue: EditablePersonValues) => {
setTechSpec('')
fetchPerson()}
const updateControlOptions = (
controls: FormControl[],
controlName: string,
newOptions: SelectOption[],
) =>
controls.map((control) =>
control.name === controlName
? { ...control, options: newOptions }
: { ...control },)
const memoizedControls = useMemo(() => {
console.info('memoizedControls')
if (personList.length > 0)
return updateControlOptions(
controls,
'personId',
personList,
)
return controls
}, [controls, personList])
const fetchPerson = () => {
const localTechSpecification = form.getFieldValue('techSpecification')
setTechSpec(localTechSpecification)
form.setFieldsValue({ personId: undefined })
}
и:
return (
{memoizedControls.map(
({ name, type, displayName, required, options, measure }) => {
return (
<MyDynamicField
key = {name}
name = {name}
controlType = {type}
displayName = {`${displayName}${measure ? `, ${measure}` : ''}`}
required = {required}
value = {value}
itemOptions = {options}
/>
)
},
)}
)
Мой вопрос заключается в том, что хук «usePerson» выполняется повторно при изменении значения состояния «techSpec». personList
обновляется. Но memoizedControls
не показывает новые значения personList
. Может быть, вы знаете, почему memoizedControls
не перерисовывается?
Пожалуйста, кто-нибудь знает, что я делаю неправильно?
@NickParsons, возможно, можно внести некоторые предложения без песочницы, потому что в песочницу нужно импортировать так много зависимостей. Спасибо за желание помочь
Вам не нужно заново создавать весь проект в codesanbox, только код, который потребуется для воспроизведения вашей проблемы. Немного сложно увидеть, что работает/не работает, не имея чего-то, с чем мы можем работать и играть. Только из этого кода я ничего не могу заметить, может быть, кто-то еще может.
@NickParsons большое спасибо. Ошибка была не в приведенном выше коде, ошибка была в компоненте MyDynamicField
import React, { useState, useMemo } from 'react';
const MyComponent = ({ personList }) => {
const [techSpec, setTechSpec] = useState('1');
const [isLoadingPersonList, setIsLoadingPersonList] = useState(false);
const handleFieldsChange = (changedValue) => {
setTechSpec('');
fetchPerson();
};
const updateControlOptions = (controls, controlName, newOptions) =>
controls.map((control) =>
control.name === controlName
? { ...control, options: newOptions }
: { ...control }
);
const memoizedControls = useMemo(() => {
console.info('memoizedControls');
if (personList.length > 0) {
return updateControlOptions(controls, 'personId', personList);
}
return controls;
}, [controls, personList]); // personList is included in the dependency array
const fetchPerson = () => {
const localTechSpecification = form.getFieldValue('techSpecification');
setTechSpec(localTechSpecification);
form.setFieldsValue({ personId: undefined });
};
return (
<div>
{memoizedControls.map(({ name, type, displayName, required, options, measure }) => (
<DynamicField
key = {name}
name = {name}
controlType = {type}
displayName = {`${displayName}${measure ? `, ${measure}` : ''}`}
required = {required}
value = {value}
itemOptions = {options}
/>
))}
</div>
);
};
да, и это желательное поведение. personList
обновляется, но memoizedControls
не показывает новые значения personList
. Может быть, вы знаете, почему memoizedControls
не перерисовывается?
компонент, который отвечает за рендеринг значения memoizedControls, использует компонент более высокого порядка PureComponent или React.memo, что предотвращает повторный рендеринг компонента, когда его реквизиты не меняются. В этом случае вы можете либо удалить компонент более высокого порядка PureComponent или React.memo, либо сделать так, чтобы компонент выполнял повторный рендеринг, изменив один из его реквизитов при изменении значения personList.
Я извиняюсь за незнание, но вы покажите, пожалуйста, это через код?
Единственное отличие, которое я нашел, это const [isLoadingPersonList, setIsLoadingPersonList] = useState(false);
, и результат тот же, элементы управления не перерисовываются.
Приведенный выше код был в порядке, проблема была в компоненте <MyDynamicField/>
.
Поэтому itemOptions
следует добавить в массив зависимостей [height, width, itemOptions])
из useEffect
. Таким образом, код будет выглядеть так:
export const MyDynamicField = ({
name,
controlType,
displayName,
required,
value,
itemOptions,
moulds,
initData,
height,
width,
}: Props) => {
const [options, setOptions] = useState<SelectOption[]>([])
useEffect(() => {
const prepareOptions = filterOptions(
name,
moulds,
initData,
itemOptions,
height,
width,
)
setOptions(prepareOptions)
}, [height, width, itemOptions])
return (
<ControlFactory
key = {name}
name = {name}
controlType = {controlType}
displayName = {displayName}
required = {required}
options = {options}
value = {value}
/>
)
}
а затем useEffect
и useState
можно удалить, а useMemo
можно использовать:
export const MyDynamicField = ({
name,
controlType,
displayName,
required,
value,
itemOptions,
moulds,
initData,
height,
width,
}: Props) => {
const options = useMemo(
() => filterOptions(name, moulds, initData, itemOptions, height, width),
[name, moulds, initData, itemOptions, height, width],
)
return (
<ControlFactory
key = {name}
name = {name}
controlType = {controlType}
displayName = {displayName}
required = {required}
options = {options}
value = {value}
/>
)
}
Было бы полезно, если бы вы создали codeandbox (или, что предпочтительнее, встроенный фрагмент кода), который воспроизводит эту проблему, чтобы мы могли помочь в отладке.