【问题标题】:perform asynchronous operations inside as a constant variable在内部作为常量变量执行异步操作
【发布时间】:2021-08-31 10:44:11
【问题描述】:

我有一个功能组件

import { DEFAULT_LANGUAGE} from './translations';
import React, { useState } from 'react';

export const Welcome= () => {
    const [appLanguage, setAppLanguage] = useState(DEFAULT_LANGUAGE);
    console.log(appLanguage);
};

translations.js

   import AsyncStorage from '@react-native-async-storage/async-storage';

    export const DEFAULT_LANGUAGE= async () => {
       try {
           const response = await AsyncStorage.getItem('appLanguage');
           if(response){
               return response;
           }
           else{
               return 'English';
           }
       }
       catch (e) {
           return 'English';
       }
    }

appLanguage 返回承诺对象而不是值。如何在内部作为常量变量执行异步操作?

【问题讨论】:

  • DEFAULT_LANGUAGE 是一个函数。你需要调用它。要在组件挂载时运行异步函数,请将 useEffect 与空依赖数组一起使用。
  • 你能做到useState(await DEFAULT LANGUAGE())吗? (你可能还需要async Welcome
  • @Grzegorz - 不,组件功能需要同步。不能在同步函数中使用await
  • @T.J.Crowder 如果你制作了const getDefLang = async () => await DEFAULT_LANGUAGE() 并在useState 中使用它会怎样?
  • @Grzegorz - 同样的问题,async 函数总是返回承诺,所以你会得到一个承诺,而不是价值。 You can't get an asynchronous result synchronously.

标签: javascript reactjs typescript react-native es6-promise


【解决方案1】:

不能DEFAULT_LANGUAGE包含实现值而不是一个promise除非你让加载模块导出它等到异步操作完成。所以你要么:

  1. 延迟完成该模块的加载,直到值可用

  2. 让它成为一个承诺并在你使用它的地方处理它

1 - 使用顶级await 延迟模块加载

只有在您的环境支持 top-level await(现在很多人都支持)的情况下,您才能这样做。

要使用它来延迟加载该模块直到异步请求完成,您可以这样做:

export const DEFAULT_LANGUAGE = await (async () => {
    try {
        const response = await AsyncStorage.getItem('appLanguage');
        if (response) {
            return response;
        } else {
            return 'English';
        }
    } catch (e) {
        return 'English';
    }
})();

也可以写成:

export const DEFAULT_LANGUAGE = await (async () => {
    let language;
    try {
        language = await AsyncStorage.getItem("appLanguage");
    } catch (e) {
    }
    return language || "English";
})();

甚至:

export const DEFAULT_LANGUAGE = await AsyncStorage.getItem("appLanguage")
    .catch(() => null)
    .then(language => language || "English");

它执行异步工作,等待它,然后允许模块加载发生。

当然,像这样延迟模块加载可能不是最佳选择,它非常取决于具体情况。但这是您唯一的选择如果您需要 DEFAULT_LANGUAGE 作为履行价值,而不是承诺。

2 - 承诺并等待它

现在,您已将 DEFAULT_LANGUAGE 设为函数。没有什么叫它。相反,调用它并存储返回的承诺:

export const DEFAULT_LANGUAGE_PROMISE = (async () => {
   try {
       const response = await AsyncStorage.getItem('appLanguage');
       if (response) {
           return response;
       } else {
           return 'English';
       }
   } catch (e) {
       return 'English';
   }
})();

然后,在使用的时候,等待promise的实现:

import { DEFAULT_LANGUAGE_PROMISE} from './translations';
import React, { useState } from 'react';

export const Welcome = () => {
    const [appLanguage, setAppLanguage] = useState(null);
    useEffect(() => {
        // We don't have to worry about rejection, because you've set it
        // up not to reject
        DEFAULT_LANGUAGE_PROMISE.then(setAppLanguage);
    }, []);
    // ...
};

请注意,Welcome 的渲染必须处理在这种情况下 appLanguage 最初将是 null 的事实。

您可能希望让您的主入口点组件处理此问题,然后通过context 将其提供给树中的所有组件。有各种不同的方法来旋转它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-20
    • 2023-02-22
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2017-06-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多