简体   繁体   English

React Native - 组件未加载

[英]React Native - Components not loading

Having a strange issue in React Native - I'm trying to build a list of cards, where each card represents a card with user information (eg first name, last name, etc).在 React Native 中遇到一个奇怪的问题 - 我正在尝试构建一个卡片列表,其中每张卡片代表一张带有用户信息(例如名字、姓氏等)的卡片。

The card is a separate component that takes an _id prop.卡片是一个单独的组件,它采用_id道具。 The _id is then used in the Card component to fetch the data.然后在 Card 组件中使用_id来获取数据。 The cards are then instantiated like this:然后像这样实例化卡片:

Card.js Card.js

import React, { useState, useEffect } from 'react';

import {
  View,
  Text,
  Image,
  StyleSheet
} from 'react-native';

const Card = (props) => {
   const [bio, setBio] = useState(true) 
   const [email, setEmail] = useState(true) 
   const [firstName, setFirstName] = useState(true) 
   const [lastName, setLastName] = useState(true) 
   const [phoneNumber, setPhoneNumber] = useState(true) 
   const [photoData, setPhotoData] = useState(true) 

   const baseUrl = "node-js-backend-url"
   const fileReaderInstance = new FileReader();
   
   loadImage = (url, headers) => {
      fetch(url, {headers})
      .then(response => response.blob())
      .then(blob => {
         fileReaderInstance.readAsDataURL(blob);
         fileReaderInstance.onload = () => {
            base64Data = fileReaderInstance.result;
            setPhotoData(base64Data);
         }
      })
      .then(() => {
         console.log("Card details: ")
         console.log(firstName)
         console.log(lastName)
      })
      .catch(error => {
         console.log("Error getting image for card: " + props._id + ", token: " + props.token+ ", "+ error)
      });
   }

   loadCardData = (url) => {
      let headers = new Headers()
      headers.append("Content-Type", "application/x-www-form-urlencoded");
      headers.append("x-auth-token", props.token)

      fetch(url, {headers})
      .then(response => response.json())
      .then(data => {
         setFirstName(data.firstName ? data.firstName : null)
         setLastName(data.lastName ? data.lastName : null)
         setBio(data.bio ? data.bio : null)
         setEmail(data.email ? data.email : null)
         setPhoneNumber(data.phoneNumber ? data.phoneNumber : null)

         var photoUrl = baseUrl + "/api/card/" + data._id + "/file/image/" + data.photo.filename;
         loadImage(photoUrl, headers)
      })
      .catch(error => {
         console.log("Error fetching card data for card: " + props._id + ", token: " + props.token + ", " + error)
         
      });
   }

   useEffect(() => {
         let url = baseUrl + "/api/card/" + props._id
         loadCardData(url)
         console.log("Successfully loaded card.")
   }, []);

  return (
    <>
         <View 
            style={cardStyles.outerView}
         >
            <View style={cardStyles.photoView}>
               <Image
                  source={{
                     uri: photoData.length > 0 ? photoData : null
                   }}
                   style={cardStyles.portrait}
               ></Image>
            </View>
            <View style={cardStyles.infoView}>
               <Text style={cardStyles.names}>{firstName} {lastName}</Text>
               <Text style={cardStyles.bio}>{bio}</Text>
               <Text style={cardStyles.contact}>{email}</Text>
               <Text style={cardStyles.contact}>{phoneNumber}</Text>
            </View>
         </View>
    </>
  );
};

const cardStyles = StyleSheet.create({
   outerView: {
      backgroundColor: '#F9F8F8',
      shadowColor: "#000",
      shadowOffset: {
         width: 0,
         height: 2,
      },
      shadowOpacity: 0.23,
      shadowRadius: 2.62,
      elevation: 4,
      borderRadius: 10,
      padding: 15,
      flexDirection: "row",
      justifyContent: "center",
      alignItems: "center"
   },
   names: {
      fontSize: 18,
      margin: 5
   },
   bio: {
      margin: 10
   },
   contact: {
      fontSize: 14
   },
   photoView: {
      flex: 0.425,
      width: 100,
      height: 100,     
      borderRadius: 250, 
      marginRight: 15,
      backgroundColor:"#FFFFFF",
      justifyContent: "center",
      alignItems: "center"
   },
   portrait: {
      flex: 1,
      width: "100%",
      height: "100%",
      resizeMode: 'contain',
      borderRadius: 100,
   },
   infoView: {
      flex: 1
   }
})

export default Card;

Connections.js Connections.js

import React, { useState, useEffect } from 'react';
import { styles } from '../styles/styles'
import Card from '../components/Card'

import {
  SafeAreaView,
  View,
  ScrollView,
  Text,
  StatusBar,
  StyleSheet
} from 'react-native';

const ContactsPage: () => React$Node = () => {
  const baseUrl = "node-js-backend-url"
  const token = "[x-auth-token-for-testing]"
  
  const [connections, setConnections] = useState([]) 
  const [loading, setLoading] = useState() 

  loadConnections = () => {
    let headers = new Headers()
    headers.append("Content-Type", "application/x-www-form-urlencoded");
    headers.append("x-auth-token", token)

    let url = baseUrl + "user/connections"
    console.log("url: " + url)

    fetch(url, {headers})
    .then(response => response.json())
    .then(data => {
      setConnections(data.connections)
      setLoading(false)
    })
    .catch(error => {
        console.log("Error fetching connections: " + error)
    });
  }
  useEffect(() => {
    setConnections([])
    setLoading(true)
    loadConnections()
  }, []);

  return (
    <>
        <StatusBar barStyle="dark-content" />
        <SafeAreaView style={styles.container}>
          <View style={styles.heading}>
            <Text style={styles.headline}>Connections</Text>
          </View>
          <ScrollView style={styles.body, cardStyles.cardList}>
            {/* {loading == true && <Text>Loading...</Text>}
            {(loading == false && connections.length == 0) && <Text>You have no connections yet! Add some to get started...</Text>}
            {(loading == false && connections.length > 0) && connections.map(connection => (<Card key={connection} _id={connection} token={token}></Card>))} */}
            {/* {( loading == false  */}
              {/* <Card key="card1" _id="6005ef770aeb9b3a7035311f" token={token} style={cardStyles.card}></Card> */}
              {/* <Card key="card2" _id="6011d9d39689ab00049fc6e8" token={token} style={cardStyles.card}></Card> */}
              {/* <Card key="card3" _id="6005ef770aeb9b3a7035311f" token={token} style={cardStyles.card}></Card> */}
              <Card key="card4" _id="6011d9d39689ab00049fc6e8" token={token} style={cardStyles.card}/>
              <Card key="card5" _id="6005ef770aeb9b3a7035311f" token={token} style={cardStyles.card}/>
          </ScrollView>
        </SafeAreaView>
    </>
  );
};

const cardStyles = StyleSheet.create({
  card: {
    marginTop: 10,
    marginBottom: 10
  },
  cardList: {
    height: "80%"
 }
})

export default ContactsPage;

控制台记录卡片数据,可以看到卡片加载成功 连接页面截图

The result is that 2 cards are rendered, however only the last card contains any information.结果是渲染了 2 张卡片,但只有最后一张卡片包含任何信息。 If I create only a single card, all the information is shown as expected.如果我只创建一张卡片,所有信息都会按预期显示。 Adding more than two cards results in all but the last being unpopulated (ie not showing the user data).添加多于两张卡会导致除最后一张之外的所有卡都未填充(即不显示用户数据)。

The interesting part is that the correct data is loaded even for cards that don't show it.有趣的是,即使对于不显示的卡片,也会加载正确的数据。 Logging the retrieval of each card's data shows that user data has been set in the state.记录每张卡数据的检索显示用户数据已设置在 state 中。 Also, the margins from the card style are not applied.此外,不应用卡片样式的边距。 What could be the case of this, and how can it be fixed?这可能是什么情况,如何解决?

You're declaring all of your data fetching functions as global variables (eg loadCardData , loadImage , loadConnections ) because you haven't added a keyword in front of them like const to define their scope.您将所有数据获取函数声明为全局变量(例如loadCardDataloadImageloadConnections ),因为您没有在它们前面添加像const这样的关键字来定义它们的 scope。

Change to:改成:

const loadCardData = (url) => 

And repeat for all instances.并重复所有实例。

Unrelated note: You may want to reconsider your use of true for the default state of all of your useState hooks.无关说明:您可能需要重新考虑对所有useState挂钩的默认 state 使用true You do a true/false comparison later on, which will end up returning true before the values are initialized.您稍后会进行真/假比较,最终将在值初始化之前返回true Consider initializing them as empty versions of the types they will become eg useState("") for a string or as undefined.考虑将它们初始化为类型的空版本,例如stringuseState("")或未定义的类型。

Without this, they go into the global scope and end up capturing only the last occurrences of setName , etc没有这个,他们 go 进入全局 scope 并最终仅捕获最后出现的setName

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

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