我正在尝试创建一个自动保存配置页面。我希望它可以加载配置文件(现在只是一个json文件)来声明,然后你可以通过ui组件对其进行编辑。当您切换到另一个页面时,状态可以保存回配置文件。我不知道如何实现它。
目前我使用
useEffect
和 []
作为第二个参数来执行此操作。根据官方文档,它将在安装组件时运行作为第一个参数传递的 setup 函数,并在卸载组件时运行返回的 clean 函数。但是,可能由于加载/保存操作是异步函数,它的运行情况与我的预期完全不同。
这是我的代码,包括一些调试日志:
const [settings, setSettings] = useState<settingStruct>({});
const loadSettings = async () => {
const savedSetting = await loadJsonFile<settingStruct>("settings.json", {});
console.log("load: ", settings);
setSettings(savedSetting!);
};
const saveSettings = async () => {
console.log("save: ", settings);
await saveJsonFile('settings.json', settings);
};
useEffect(() => { // here I hope it could achieve auto-load/save
loadSettings();
return () => {
saveSettings();
}
}, []);
useEffect(()=>{
console.log("changed: ", settings)
}, [settings]);
另外,我临时添加了一个可以手动触发运行的按钮
saveSettings()
。
然后,经过测试,我得到的控制台日志如下:
// switch to the page
changed: {} // init value
save: {} // react's strict mode, run an additional setup and cleaner, however the order is wrong
changed: {} // not sure why it's triggered
load: {} // two setup and changes caused by them
changed: {}
load: {}
changed: {}
changed: {authKey: '1234567'} // here I pasted something to input component, and it triggered state update operation
save: {authKey: '1234567'} // manual save, it looks good
save: {} // cleaner triggered because I switched to another page, but it saved an empty object(specifically the init value), not the latest state
有两个问题,第一是严格模式的
setup -> cleaner -> setup
调用顺序错误,我相信这是因为它们是异步函数,所以react不知道前面的没有完成。它导致初始化值在加载值更新之前被保存,我不知道如何修复它。不过在生产环境中似乎不是问题。
第二个问题,我完全无法理解,是组件卸载时触发的清理器,总是只保存初始化值,无论实际状态是什么。这导致我的功能完全不可用
我想知道如何解决这些问题,或者如何正确实现这个自动保存功能。
请尝试介绍
settingsRef
,当settings
发生变化时,它会更新。 settingsRef.current
用于 saveSettings
。
const [settings, setSettings] = useState<settingStruct>({});
const settingsRef = useRef(settings);
const saveSettings = async () => {
await saveJsonFile('settings.json', settingsRef.current);
};
useEffect(() => {
loadSettings();
return () => {
saveSettings();
}
}, []);
useEffect(()=>{
console.log("changed: ", settings)
settingsRef.current = settings; // update settingsRef
}, [settings]);