如何在React Native中从API调用副作用中更新我的状态?

huangapple go评论69阅读模式
英文:

how do I update my state from an API call side Effect in React native?

问题

我有一段代码,使用 useEffect 钩子从 Firebase 存储获取文件列表的元数据,然而,在 useEffect 中更新我的状态似乎有困难。我已经尝试了 async/await 模式来解决 setState 的异步性质,但没有太大成功。

我的伪代码片段如下:

const [someData, setSomeData] = useState([]);
const dataArray = [];

useFocusEffect(
  useCallback(() => {
    async function getData() {
      const result = await listAll(storageRef);
      await result.items.map(async (itemRef) => {
        const Metadata = await getMetadata(itemRef);
        await dataArray.push({ 'name': Metadata.name });
        await console.log(dataArray); // 在每次迭代中显示数组被填充
      });
      await setSomeData(dataArray);
      await console.log(someData); // 我期望它打印出更新后的状态,但实际上打印一个空数组
    }
    getData();
  }, [])
);

此外,我似乎也无法在代码的返回部分访问状态:

return (
  {someData.map(({ item }) => {
    return (
      <View><Text>{item.name}</Text></View>
    );
  })}
);

根据我所看到的,这似乎没有输出任何内容。

在我的方法中漏掉了什么?

提前感谢。

英文:

I have a piece of code that gets Metadata of a list of files from Firebase storage using the useEffect hook. I however, struggle to update my state within this useEffect. I have used the async/await pattern to mitigate the asynchronous nature of setState without much success.

My snippet in pseudocode:

const [someData,setSomeData]=useState([])
const dataArray=[]

useFocusEffect(
    useCallback(()=&gt;{
        async function getData(){
            const result=await listAll(storageRef);
            await result.items.map(async (itemRef)=&gt;{
                const Metadata=await getMetadata(itemRef);
                await dataArray.push({&#39;name&#39;:Metadata.name})
                await console.log(dataArray) //shows the array being populated on each iteration
            })
            await setSomeData(dataArray);
            await console.log(someData) // I&#39;m expecting it to print an updated state, prints an empty array instead
            }
            getData()
        },[])
    )

I also cannot seem to access the state in the return part of my code:

return(
    {someData.map(({item})=&gt;{
        return(
            &lt;View&gt;&lt;Text&gt;{item.name}&lt;/Text&gt;&lt;View&gt;)})

outputs nothing as far as I can tell.

What am I missing in my approach?

Thanks in advance

答案1

得分: 0

  • setSomeData()不返回Promise,因此无法等待。
  • dataArray需要在getData()内部作用域中。
  • getData封闭了someData,因此它永远不会获取到更新的值,因为该函数调用是指向先前的值。
  • 可能更容易使用一个与React Native兼容的异步数据库
英文:
  • setSomeData() does not return a promise, thus cannot be awaited.
  • dataArray needs to be scoped inside getData()
  • getData closes around someData, so it will never get the updated value
    as that function call is referring to the previous value
  • it might be easier to use a react native compatible async data library

答案2

得分: 0

dataArray 在每次渲染时都被重新初始化为 [],然后你将 someData 设置为 dataArray,实际上是将 someData 设置为空数组。我认为如果你将异步映射包装在 Promise.all 中,那么可以使 dataArray 作用域限定在你的 getData 函数中:

const fetchData = useCallback(() => {
  async function getData() {
    const result = await listAll(storageRef);
    const dataArray = await Promise.all(
      result.items.map(async (itemRef) => {
        const Metadata = await getMetadata(itemRef);
        console.log(Metadata);
        return { name: Metadata.name };
      })
    );
    console.log("dataArray:\n", dataArray);
    setSomeData(dataArray);
    // 即使你等待 setSomeData,someData 也不会是更新后的值。
    /*  如果你想查看 someData 的变化,可以这样做
      useEffect(() => {
        console.log(someData)
      }, [someData])
    */
  }
  getData();
}, []);
useFocusEffect(fetchData);
英文:

dataArray is being re-initialized to [] every render, and then you are setting someData to dataArray, effectively setting someData to an empty array. I think if you wrap your async map in a Promise.all then you can have dataArray scoped to your getData function:

const fetchData = useCallback(() =&gt; {
  async function getData() {
    const result = await listAll(storageRef);
    const dataArray = await Promise.all(
      result.items.map(async (itemRef) =&gt; {
        const Metadata = await getMetadata(itemRef);
        console.log(Metadata);
        return { name: Metadata.name };
      })
    );
    console.log(&quot;dataArray:\n&quot;, dataArray);
    setSomeData(dataArray);
    // even if you await setSomeData, someData wont be the the updated value. 
    /*  If you want to see someData changes do
      useEffect(()=&gt;{
        console.log(someData)
      },[someData])
    */
  }
  getData();
}, []);
useFocusEffect(fetchData);

huangapple
  • 本文由 发表于 2023年1月9日 02:57:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/75050496.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定