简体   繁体   English

如何显示异步 function 的结果

[英]How to display the result of an async function

I am trying to learn React Native and Google's firebase.我正在尝试学习 React Native 和 Google 的 firebase。 I have been able to successfully create users and I have a function that successfully gets all users and logs their username to the console.我已经能够成功创建用户,并且我有一个 function 可以成功获取所有用户并将他们的用户名记录到控制台。 However, I am having a lot of trouble finding a way to display the list of user names to the screen.但是,我很难找到一种将用户名列表显示到屏幕上的方法。

I think that a lof of my trouble stems from the fact that I am using a functional component instead of a class component which is what I see similar questions using and so far I've had kind of a hard time translating between the two.我认为我的大部分麻烦源于我使用的是功能组件而不是 class 组件,这是我看到类似问题使用的组件,到目前为止,我很难在两者之间进行转换。

I have this in my firebase methods file:我的 firebase 方法文件中有这个:

firebase/index.js firebase/index.js

export const getAllUsers = () => firebase.firestore().collection('users').get(); 

And I have this screen that currently calls a function that gets all usernames and logs them to the console.我有这个屏幕,当前调用 function 获取所有用户名并将它们记录到控制台。 What I want, is to be able to access the username (and maybe even the Role and age) and create something like Text></Text elements with them.我想要的是能够访问用户名(甚至可能是角色和年龄)并使用它们创建类似 Text></Text 元素的内容。 So something like Text>users.userName>/Text>.所以像 Text>users.userName>/Text> 这样的东西。

CharacterSelectScreen.js CharacterSelectScreen.js

import React, {useState} from 'react'
import { StyleSheet, Text, View, TouchableOpacity, TextInput, Button, Picker, ScrollView} from 'react-native'
import { NavigationContainer, useNavigation, useRoute } from '@react-navigation/native';
import * as firebase from '../../firebase'; 

const CharacterSelectScreen = ({navigation, route}) => {
    
       React.useEffect(()=>{
        console.log('Select Screen loaded.')
        userFetch();
      },[])

    const userFetch = async () => {
        try{
            const users = await firebase.getAllUsers();
            // users is a QuerySnapshot
            if (users.size > 0) {
                users.forEach(doc => {
                    userList.push(doc.data().userName);
                })
            }

        } catch (error) {
            console.log(error);
        }
        userList.forEach(item => console.log(item)); //usreList contains all of the names. This works.
        return userList;
    }


    return (
        <View style={{ flex: 1, justifyContent: 'flex-start' }}>
            <Text>Select a character:</Text>
      </View>
    )
}


export default CharacterSelectScreen;

I'm unsure how I can take the result of the async function userFetch and assign it to a usable array that I could look over.我不确定如何获取异步 function userFetch的结果并将其分配给我可以查看的可用数组。 Maybe something like this:也许是这样的:

var names = userFetch();
        return (
            <ul>
                {names.map(function(name, index){
                    return <li key={ index }>{name}</li>;
                  })}
            </ul>
        )
    }
});

But maybe this isn't even the best approach.但也许这甚至不是最好的方法。 If it's not I am up for learning/changing whatever I just need pointed in the right direction.如果不是,我愿意学习/改变我只需要指向正确方向的任何东西。

If I understand your question correctly, you may require the following pattern:如果我正确理解您的问题,您可能需要以下模式:

const Foo = () => {
  const [results, setResults] = useState([]);

  useEffect(() => {
    const asyncFunc = async () => {
      const response = await fetch(ENDPOINT);
      const { results } = await response.json();

      setResults(results);
    }

    asyncFunc();
  }, [deps];  

  return (
    <>
      {results.map((result) => <Bar result={result}/>)}
    </>
  )
}

A possible solution is to leverage React's diffing algorithm to automatically render the desired user information (through interpolation in your return).一种可能的解决方案是利用 React 的 diffing 算法自动呈现所需的用户信息(通过在您的返回中进行插值)。 This can be done by instantiating a variable that evaluates based on a conditional using your component's current state.这可以通过使用组件的当前 state 实例化一个基于条件评估的变量来完成。 If this conditional evaluates to true it returns a child component for each user in your fetched response ( UserIndexItem ).如果此条件评估为true ,它会为您获取的响应 ( UserIndexItem ) 中的每个用户返回一个子组件。

As for convention , I recommend abstracting your #userFetch through a container component that passes the method as a property to your CharacterSelectScreen so that you can DRY up your code better.至于约定,我建议通过容器组件抽象您的#userFetch ,该容器组件将该方法作为属性传递给您的CharacterSelectScreen ,以便您可以更好地干燥您的代码。 Example: Use of #useEffect that sets the state to #userFetch 's return value.示例:使用#useEffect将 state 设置为#userFetch的返回值。 This goes in line with separating concerns in your code.这符合在您的代码中分离关注点。

If you want to use what you have, I refactored your original code to execute the solution, let me know how it works for you.如果你想使用你所拥有的,我重构了你的原始代码来执行解决方案,让我知道它是如何为你工作的。

See below for snippet.请参阅下面的片段。

 import React, { useState } from 'react' import { StyleSheet, Text, View, TouchableOpacity, TextInput, Button, Picker, ScrollView } from 'react-native' import { NavigationContainer, useNavigation, useRoute } from '@react-navigation/native'; import * as firebase from '../../firebase'; import UserIndexItem from '...'; // The above import is pseudocode on how you would import a component const CharacterSelectScreen = ({ navigation, route }) => { const [ users, updateUsers ] = useState([]) useEffect(() => { console.log('Select Screen loaded.') updateUsers( userFetch() ) }, []) // Great use of #useEffect to simulate React's #componentDidMount const userFetch = async () => { try { let userCollection = [] const fetchedUsers = await firebase.getAllUsers(); // unless #getAllUsers automatically returns JSON then we need to ensure its formatted for parseable data const usersJSON = await fetchedUsers.json() usersJSON.forEach( userObject => { userCollection.push( userObject.data() ); }) return userCollection } catch (error) { console.log(error); } } // The below conditional allows us to safely apply // logic on undefined receivers because of the ternary // condition. On re-render of our component, this function will // return child components instead. const userIndex = users.length?= 0. users.map( user => { // where we can deconstruct the user object for DRYer code return ( <UserIndexItem key={user.id} username={user:username} /> ) }): <span> No Users Yet,</span> return ( <View style={{ flex: 1; justifyContent: 'flex-start' }}> <ul> { userIndex } </ul> </View> ) } export default CharacterSelectScreen;

For React convention on mapping components from an array, see: https://reactjs.org/docs/lists-and-keys.html有关从数组映射组件的React 约定,请参阅: https://reactjs.org/docs/lists-and-keys.html

Now , you can do what @AsherLim did in their return block with ghost tags but any inline functions in a component's render function will cause an unintentional re-render of your component every time there is a change to its parent component (This can lead to performance issues).现在,您可以使用幽灵标签在其返回块中执行 @AsherLim 所做的操作,但组件渲染 function 中的任何内联函数都会导致您的组件在其父组件发生更改时意外重新渲染(这可能导致性能问题)。 Reference to this claim can be found here: https://medium.com/@Osterberg/react-component-renders-too-often-2917daabcf5可以在此处找到对此声明的引用: https://medium.com/@Osterberg/react-component-renders-too-often-2917daabcf5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM