#reactjs #react-functional-component
Вопрос:
У меня есть функциональный компонент, использующий крючок useEffect для подписки на внешнее событие, и это внешнее событие использует значение в реквизитах компонентов. Я не понимаю, почему сам компонент при рендеринге использует обновленное значение реквизита, но мой обратный вызов использует исходное значение.
Я подумал, что, возможно, мне нужно изменить второй параметр useEffect, чтобы указать реквизиты, однако это не имеет никакого значения.
В приведенном ниже примере обратный вызов OnSave вызывается и пытается использовать текущее значение props.ModelName, однако, даже если сам компонент имеет обновленное значение, обратный вызов, похоже, видит только исходное значение этого свойства.
Это почему? Это как-то связано с закрытием или я упускаю что-то еще?
useEffect(() => {
EventBus.on(EventIds._designerSaveCommand, onSave);
return () => {
EventBus.remove(EventIds._designerSaveCommand, onSave);
};
}, [reactFlowInstance,props]);
И у меня есть такой обработчик событий:
const onSave = () => {
try {
const object = reactFlowInstance?.toObject();
if(object) {
const exportedModel: IExportedModel = {
modelName: props.modelName, <---- This is not the current value in the component props
model: object
};
const json = JSON.stringify(exportedModel);
var blob = new Blob([json], { type: "application/json" });
FileSaver.saveAs(blob, `${props.modelName}.json`);
}
}
catch(e) {
setMessage({text: e.message, type: MessageBarType.error});
}
};
Комментарии:
1. Ну, я заставил это работать с помощью React.useRef, который, как я полагаю, является правильным подходом здесь, но оставлю его открытым для того, чтобы кто-нибудь сказал мне что-то другое
Ответ №1:
У вас есть правильная идея, добавив prop в массив зависимостей. Вам также нужно переместить функцию onSave()
внутрь крючка. Затем он будет ссылаться на последнюю modelName
версию .
useEffect(() => {
const onSave = () => {
try {
const object = reactFlowInstance?.toObject();
if(object) {
const exportedModel: IExportedModel = {
modelName: modelName,
model: object
};
const json = JSON.stringify(exportedModel);
var blob = new Blob([json], { type: "application/json" });
FileSaver.saveAs(blob, `${modelName}.json`);
}
}
catch(e) {
setMessage({text: e.message, type: MessageBarType.error});
}
};
EventBus.on(EventIds._designerSaveCommand, onSave);
return () => {
EventBus.remove(EventIds._designerSaveCommand, onSave);
};
}, [reactFlowInstance, modelName]);
Если вам не нравится useEffect
so big, вы можете отделить только логику файла от новой функции и вызвать ее внутри крючка следующим образом:
useEffect(() => {
const onSave = () => {
saveFile(reactFlowInstance, modelName)
};
// ... handlers go here
}, [reactFlowInstance, modelName]);