当组件要被卸载时,如何通过异步函数将某些内容保存到本地存储

问题描述 投票:0回答:1

我正在尝试创建一个自动保存配置页面。我希望它可以加载配置文件(现在只是一个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不知道前面的没有完成。它导致初始化值在加载值更新之前被保存,我不知道如何修复它。不过在生产环境中似乎不是问题。

第二个问题,我完全无法理解,是组件卸载时触发的清理器,总是只保存初始化值,无论实际状态是什么。这导致我的功能完全不可用

我想知道如何解决这些问题,或者如何正确实现这个自动保存功能。

reactjs
1个回答
0
投票

请尝试介绍

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]);
© www.soinside.com 2019 - 2024. All rights reserved.