【问题标题】:Not able to change React state using useState无法使用 useState 更改 React 状态
【发布时间】:2020-07-08 02:05:20
【问题描述】:

我在使用 React Native 和 Expo 获取用户位置时进行了条件渲染。单击按钮以显示微调器后,我正在更改状态,但是由于某种原因,我的状态变量始终为 false。我了解 useEffect 钩子,但是我认为我不需要在任何特定的生命周期中更改变量。这是正确的推理吗?起初我认为这是由于函数的异步性质,但它似乎不太可能。

状态初始化

const [loading, toggleLoading] = useState(false);

onClick 代码

{props.location === null ? (
        <Button onPress={getLocationAsync} mode="contained">
          Get Location
        </Button>
      ) : loading === true ? (
        <Button mode="contained">
          <ActivityIndicator />
        </Button>
      ) : (
        <Button mode="outlined">Received</Button>
      )}

getLocationAsync 的代码

const getLocationAsync = async () => {
    toggleLoading(true);
    let { status } = await Permissions.askAsync(Permissions.LOCATION);

    if (status !== "granted") { }

    let location = await Location.getCurrentPositionAsync();
    toggleLoading(false);
  };

在任何地方记录状态总是会导致加载为假。在这种情况下,我真的需要类似 useEffect 的东西吗?

【问题讨论】:

    标签: javascript reactjs react-native expo


    【解决方案1】:

    你确定它不起作用吗? React 中的State 也是异步的,所以你的console.log() 可能不准确。

    我已经 created simple example 使用您的代码,它运行良好。唯一可能不同的是您的三元状态。您看不到“正在加载”,因为您的第一个条件是 location === null,即使在加载时也是 null。我刚刚修改了你的第一个条件:location === null &amp;&amp; loading !== true 并且工作正常。

    【讨论】:

    • 太有趣了!问题确实出在我显示条件渲染的逻辑上。但是,我仍然对 console.log 总是错误的感到有些困惑。即使在异步调用之后,我的组件是否应该在状态更改后重新呈现,这仍然应该给我真实的情况?
    • @YashankVarshney 取决于您在哪里记录您的状态。如果您将console.log() 放在return 之前,您将在加载时看到false,在单击后看到true,在异步功能完成后看到false。您也可以使用状态更改后立即调用的state's callback function
    • 这就是问题所在。控制台日志记录总是向我显示 false 作为输出。在初始渲染和状态更改之后。通常这不会是一个问题,但在这种情况下它是。
    【解决方案2】:

    在 React 中设置状态是异步的!这就是为什么您的日志显示false

    const onPress = () => toggleLoading(true)
    
    useEffect(() => {
      const getLocationAsync = async () => {
        // your actions here
        toggleLoading(false)
      }
      if (loading) getLocationAsync()
    }, [loading])
    
    // in your render
    <Button {...{ onPress}} mode="contained">Get Location</Button>
    

    如果你这样做,你就 100% 确定你的 getLocationAsync() 代码只有在 loading === true 时才会执行!

    【讨论】:

    • 是的,您完全正确地认为状态是异步的,因此日志显示为 false。我确实让逻辑部分正常工作,所以谢谢!
    【解决方案3】:

    你可以试试

    onPress={() => {
       toggleLoading(true);
       getLocationAsync();
    }}
    

    【讨论】:

    • 以这种方式调用函数有趣的是根本没有调用任何函数......我想知道这是否是由于异步调用造成的?
    • 在渲染方法中使用匿名箭头函数是一种不好的做法,因为它们总是在每次渲染时重新分配!
    猜你喜欢
    • 2019-10-17
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 2020-09-05
    • 2020-05-12
    • 2019-08-06
    相关资源
    最近更新 更多