【问题标题】:react native state not changing反应原生状态不变
【发布时间】:2020-06-18 21:33:41
【问题描述】:

我想使用钩子将字符串从asyncstorage 传递给状态变量,但它不起作用,尝试了几个小时但仍然不起作用。 这是代码:

const [cartitems, cartitemsfunc] = useState('');

const d = async () => {
let items = await AsyncStorage.getItem('items');
console.log('items from cart:' + items);
cartitemsfunc(items);
console.log('items from cart2:' + cartitems);
 };

d();

当我尝试控制台记录 cartitems 时,它会在控制台中记录一个空字符串,但 items 会注销该字符串

谁能告诉我哪里出错了

提前谢谢!!!

【问题讨论】:

  • 在cartitemsfunc(items);前面添加await,如果你想要加速的console.log,因为cartitemsfunc也是async。
  • useState 不同步。 cartitemsfunc(items) 是异步运行的,因此在下一行运行 console.log 之前可能不会更新值
  • @CevaComic 我试过了,我没有工作
  • @SamuelG 所以你建议我怎么做,因为我不能使用函数外的项目,我也不能使用函数外的状态

标签: reactjs react-native react-hooks asyncstorage


【解决方案1】:

正如所提供的 cmets 和 link 中所述,useState 是异步的,因此在以下行中设置一个值并立即读取它不会产生一致的结果:

cartitemsfunc(items); // async call
console.log('items from cart2:' + cartitems); // cartitems not updated yet

同样重要的是要了解,每当您使用useState 更新状态时,组件都会再次呈现。如果您在应用程序主体中有一个方法调用,它将在您每次更新状态时运行。因此,您所拥有的是一个场景,您正在调用更新状态,但该方法正在执行并最终覆盖您的更改。

const d = async () => {
let items = await AsyncStorage.getItem('items');
console.log('items from cart:' + items);
cartitemsfunc(items);
console.log('items from cart2:' + cartitems);
 };

d(); // this will run every time the component renders - after you update state

如果您只需要初始渲染时的值,则从useEffect 调用该方法并将依赖链设置为[],这样它只会在首次渲染时运行一次,而不是每次更新状态时。

下面的示例演示了从 localStorage 获取/设置值以及直接更新状态。

CodeSandbox Demo

import React, { useState, useEffect } from "react";
import AsyncStorage from "@react-native-community/async-storage";
import "./styles.css";

export default function App() {
  const [cartItems, setCartItems] = useState(null);

  const setLSItems = async () => {
    await AsyncStorage.setItem(
      "items",
      JSON.stringify([{ id: "foo", quantity: 1 }, { id: "bar", quantity: 2 }])
    );

    getLSItems(); // or setCartItems("Foo");
  };

  const clearLSItems = async () => {
    await AsyncStorage.removeItem("items");

    getLSItems(); // or or setCartItems(null);
  };

  const getLSItems = async () => {
    const items = await AsyncStorage.getItem("items");

    setCartItems(JSON.parse(items));
  };

  // bypass using local storage
  const setCartItemsDirectly = () => {
    setCartItems([{ id: "baz", quantity: 3 }]);
  };

  useEffect(() => {
    getLSItems();
  }, []); // run once at start

  return (
    <div className="App">
      <div>
        <button onClick={setLSItems}>Set LS Items</button>
        <button onClick={clearLSItems}>Clear LS Items</button>
      </div>
      <div>
        <button onClick={setCartItemsDirectly}>Set Cart Items Directly</button>
      </div>
      <hr />
      {cartItems &&
        cartItems.map((item, index) => (
          <div key={index}>
            item: {item.id} | quantity: {item.quantity}
          </div>
        ))}
    </div>
  );
}

【讨论】:

  • 它可以工作,但是一旦我收到错误并重新加载它就会停止工作,我认为这是一个不同的问题
  • 您的代码出现错误 - 或者您在沙码盒演示中看到了该错误?
  • 我的代码出现错误,但它的工作我不知道是否有办法隐藏反应本机中的错误,例如在 Web 应用程序中如何显示错误但代码仍然运行
  • 所以终于解决了,添加了一个 try catch 语句,它隐藏了错误,现在一切正常,非常感谢@samuel G
【解决方案2】:

由于setState 是异步的,您需要观察它何时完成,这可以使用useEffect 并将caritems 添加到依赖项数组中轻松完成

const [cartitems, cartitemsfunc] = useState('');

const d = async () => {
  let items = await AsyncStorage.getItem('items');
  console.log('items from cart:' + items);
  cartitemsfunc(items);
};

useEffect(()=> {
 console.log('items from cart2:' + cartitems);
}, [caritems]);

d();

【讨论】:

    【解决方案3】:

    我认为这里的 console.log() 语句是在更新状态之前执行的。因为这里已经使用了 await,所以它会在得到结果之前执行下一行。

    因此,在这种情况下,我们使用 useEffect() 和 useState() 的组合。 useEffect() 用于获取数据,useState() 用于更新状态并重新渲染 UI。

    【讨论】:

    • 我如何使用useEffect获取数据请你写代码谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 2021-03-23
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多