Вы почти наверняка не должны хранить его в состоянии. Реквизит по существу контролируется родителем. Просто используйте его из реквизита. Копирование реквизита в состояние обычно не лучший вариант. практика.
Если вы столкнулись с одной из очень редких ситуаций, когда имеет смысл устанавливать производное состояние на основе свойств, на этой странице в документации рассказывается, как это сделать с помощью хуков. По сути, вы не используете useEffect
, вы сразу же обновляете свое состояние.
Вот полная цитата из связанной документации:
Как реализовать getDerivedStateFromProps?
Хотя вам, вероятно, это не нужно, в редких случаях (например, при реализации компонента <Transition>
) можно обновить состояние прямо во время рендеринга. React повторно запустит компонент с обновленным состоянием сразу после выхода из первого рендеринга, поэтому это не будет дорого.
Здесь мы сохраняем предыдущее значение свойства строки в переменной состояния, чтобы мы могли сравнить:
function ScrollView({row}) {
const [isScrollingDown, setIsScrollingDown] = useState(false);
const [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// Row changed since last render. Update isScrollingDown.
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
На первый взгляд это может показаться странным, но обновление во время рендеринга — это именно то, чем концептуально всегда был getDerivedStateFromProps.
Если вы сделаете это так же, как в этом примере, ваш компонент все равно будет отображаться с containerName
, установленным в состояние по умолчанию (""
), просто он будет почти сразу повторно отображаться с обновленным containerName
. Это имеет смысл для их примера перехода, но вы можете избежать этого, сделав значение свойства initial значением состояния initial, например так:
const DataGrid = (props) => {
const [containerName, setContainerName] = useState(props.containerName); // *** ONLY USES THE INITIAL PROP VALUE
const [frameworkComponents, setFrameworkComponents] = useState(
// ...
});
// *** Updates the state value (on the next render) if the prop changes
if (containerName !== props.containerName) {
setContainerName(props.containerName);
}
// ...
};
Однако каждый раз, когда реквизит containerName
изменяется, ваш компонент будет рендериться дважды, что возвращает нас к следующему: не хранить его в состоянии, просто использовать его из реквизита. :-)
Отступая назад и глядя на компонент в целом, я не думаю, что вам вообще нужна какая-либо информация о состоянии, но если ваша цель состоит в том, чтобы избежать ненужного изменения frameworkComponents
, которое вы передаете UxDataGrid
, вы, вероятно, захотите useMemo
или React.memo
, а не состояние.
Например, с useMemo
(но продолжайте читать):
const DataGrid = ({containerName}) => {
const frameworkComponents = useMemo(() => {
const onDeleteSetting = async (settingKey) => {
console.log("ON DELETE AND CONTAINER NAME:");
console.log(containerName);
// ...
};
return {
customLoadingOverlay: LoadingOverlayTemplate,
editButton: params => <ViewAndDeleteSetting {...params}
openAddConfigurationsWindow={openAddConfigurationsWindow}
onDeleteSetting={onDeleteSetting} />,
};
}, [containerName]);
return (
<UxDataGrid frameworkComponents={frameworkComponents} />
);
};
Но если componentName
— ваша единственная опора, с React.memo
может быть еще проще:
const DataGrid = React.memo(({containerName}) => {
const onDeleteSetting = async (settingKey) => {
console.log("ON DELETE AND CONTAINER NAME:");
console.log(containerName);
// ...
};
return (
<UxDataGrid frameworkComponents={{
customLoadingOverlay: LoadingOverlayTemplate,
editButton: params => <ViewAndDeleteSetting {...params}
openAddConfigurationsWindow={openAddConfigurationsWindow}
onDeleteSetting={onDeleteSetting} />,
}} />
);
});
React.memo
запоминает ваш компонент, так что функция вашего компонента вызывается снова только при изменении реквизита. Поскольку все в компоненте необходимо обновить на основе изменения свойства componentName
, это выглядит как хорошее совпадение (но я не знаю, что такое UxDataGrid
).
person
T.J. Crowder
schedule
12.01.2021
containerName
в обработчикеonDeleteSetting
пусто, потому что ваша переменнаяframeworkComponents
установлена только изначально. Даже если вы попытаетесь установить его после вызоваsetContainerName
, ReactuseState
обновит не сразу. Если вы действительно хотите сделать что-то подобное, вы можете добавить еще одинuseEffect
сcontainerName
в качестве зависимости и вызвать в немsetFrameworkComponents
. Но вся ваша структура кода выглядит как плохая практика, попробуйте провести рефакторинг, чтобы не устанавливать целые компоненты в свойstate
- person Kapobajza   schedule 12.01.2021