'problems loading data in ScrollView

I want to make a ScrollView that uses data that it async fetches from my backend. But for the moment when I try to render the subject, or even log the subjects, it gives as a return null... I don't know how to make my function wait until it gets the subject. Any ideas how to fix it?

return(
    <ScrollView >
        {console.log(subjects)}
        {subjects.map(renderSubject)}
    </ScrollView>
)

  const renderSubject = ({subject}) => {
    {console.log(subject)}
    return(
        <View style={styles.subjectTotalBlock}>
            <Text style={styles.students}>
                Students: {subject.nrOfStudents}
            </Text>
            <Text style ={styles.title}>
                {subject.name}
            </Text>
            <ReadMore
                numberOfLines={3}
                renderTruncatedFooter={_renderTruncatedFooter}
                renderRevealedFooter={_renderRevealedFooter}
                onReady={_handleTextReady}>
                <Text style={styles.shortDescription}>
                    {subject.description}
                </Text>
            </ReadMore>
        </View>
    );
}

This is the function that gets the subjects.

React.useEffect(()=> {
    const constructor = async () => {
        await refreshToken();
        let token = await getToken();
        let axios = require('axios');

        let config = {
            method: 'get',
            url: 'http://' + ipCamp + ':' + portNr + 
                '/subjectManagement/subjects',
            headers: {
                'Authorization': 'Bearer ' + JSON.parse(token)
            }
        };
        axios(config)
            .then(function (res) {
                setSubjects(res.data);
                setHasloaded(true);
                //console.log(res.data);
            }).catch(function (error) {
        });
    }
    constructor();
},[])


Solution 1:[1]

the reason is "renderSubject" is not going to reRender so you see null in your log. if you see the data in the line below:

//console.log(res.data);

I suggest you use FlatList instead of the map function:

const SubjectsScreen = () => {
  const [subjects, setSubjects] = React.useState([])
  React.useEffect(() => {
    const constructor = async () => {
      await refreshToken();
      let token = await getToken();
      let axios = require('axios');

      let config = {
        method: 'get',
        url: 'http://' + ipCamp + ':' + portNr + '/subjectManagement/subjects',
        headers: {
          Authorization: 'Bearer ' + JSON.parse(token),
        },
      };
      axios(config)
        .then(function (res) {
          setSubjects(res.data);
          setHasloaded(true);
          //console.log(res.data);
        })
        .catch(function (error) {});
    };
    constructor();
  }, []);

  const Subject = ({subject}) => {
    return (
      <View style={styles.subjectTotalBlock}>
        <Text style={styles.students}>Students: {subject.nrOfStudents}</Text>
        <Text style={styles.title}>{subject.name}</Text>
        <ReadMore
          numberOfLines={3}
          renderTruncatedFooter={_renderTruncatedFooter}
          renderRevealedFooter={_renderRevealedFooter}
          onReady={_handleTextReady}>
          <Text style={styles.shortDescription}>{subject.description}</Text>
        </ReadMore>
      </View>
    );
  };
  
  return (
    <FlatList
      data={subjects}
      keyExtractor={item => item.id}
      renderItem={({item}) => {
        return <Subject subject={item} />;
      }}
    />
  );
};
export default SubjectsScreen;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1