Satyaki Das
Satyaki Das

Reputation: 157

FlatList in react native not rendering data from state

FlatList is not rendering data from state however it is working for the DATA variable. this.state.DATA is an array of objects just like the DATA variable.The DATA variable is just a dummy variable that was given in the reactnative docs. I want to display the contents of this.state.DATA.

import React, { Component } from 'react';
import { Text, View ,FlatList} from 'react-native';
import SectionHeader from '../SectionHeader';
import {TableHeader,TableHeaderText,IssueContainer} from './style';
import {CheckOutlined,InfoCircleOutlined,CaretDownOutlined} from '@ant-design/icons'
const DATA = [
    {
      id: '1',
      title: "No show password eye button in Login form",
    },
    {
      id: '2',
      title: 'Second Item',
    },
    {
      id: '3',
      title: 'Third Item',
    },
  ];
var repos=[],issues=[];
export default class App extends Component {
    state={isLoading:true};
  componentDidMount() {
    fetch('https://api.github.com/orgs/anitab-org/repos')
    .then((response)=>response.json())
    .then((json)=> json.forEach(function(repo,idx){
        repos.push(repo.name);
        fetch('https://api.github.com/repos/anitab-org/'+repo.name+'/issues')
        .then((response)=>response.json())
        .then((json)=>json.forEach(function(issue,idx){
            var flag=false;
            var issue_tmp={
                id:issue.id.toString(),
                url:issue.html_url,
                title:issue.title,
                milestones:issue.milestones,
                comments:issue.comments,
                number:issue.number,
                assignees:issue.assignees,
                labels:[],
            };
            issue.labels.forEach(function(label){
                if(label.name==="First Timers Only")
                    flag=true;
                issue_tmp.labels.push({
                    id:label.id,
                    name:label.name,
                    color:label.color
                })
            })
            if(flag===true && issue_tmp!=null)
                issues.push(issue_tmp)
        }));
    }))
    .then(()=>{
        this.setState({
            repos:repos,
            DATA:issues,
            isLoading:false,
        });
    })
  }
  render() {
    if(this.state.isLoading===true)
        return(<></>)
    else{
        return (
            <View style={{alignItems: 'left',width:'80%'}}>
                <SectionHeader title="SOME COOL FIRST-TIME ISSUES TO WORK ON"/>
                <TableHeader>
                    <TableHeaderText style={{color:'#000',textAlign:'left'}}><InfoCircleOutlined /> 5 Open</TableHeaderText>
                    <Text style={{flex:6,color:'#586069'}}><CheckOutlined /> 45 Closed</Text>
                    <TableHeaderText>Author <CaretDownOutlined /></TableHeaderText>
                    <TableHeaderText>Label <CaretDownOutlined /></TableHeaderText>
                    <TableHeaderText>Milestone <CaretDownOutlined /></TableHeaderText>
                    <TableHeaderText>Assignee <CaretDownOutlined /></TableHeaderText>
                    <TableHeaderText>Sort <CaretDownOutlined /></TableHeaderText>
                </TableHeader>
                <FlatList
                    data={this.state.DATA}
                    renderItem={({item})=>(
                        <IssueContainer key={item.id}><Text>{item.title}</Text></IssueContainer>
                        )}
                    keyExtractor={item => item.id}
                />
            </View>
            );
        }
    }
};

Upvotes: 1

Views: 546

Answers (1)

buzatto
buzatto

Reputation: 10382

The reason it doesn't work is because you have nested promises. The outer then won't wait the inner ones to execute the following code. This way last then with setState is executed without those promises being resolved:

.then((json)=> json.forEach(function(repo,idx){
    // bunch of promises being executed here with some chained then blocks
    // outer 'then' chain doesn't wait these promises to resolve
}))
.then(()=>{
    // since the previous one doesn't wait its inner promises to execute
    // this chained 'then' is executed without those promises return their values
    this.setState({
        repos:repos,
        DATA:issues,
        isLoading:false,
    });

I rewrote your code with async/await because with some many promises it's a hard read. I use Promise.all to wrap all fetches. Also I abstracted your issue treatment to its own normalize function:

  state = { 
    isLoading: true,
    repos: [],
    DATA: [],

  };

  async componentDidMount() {
    const repos = [];
    try {
      const response = await fetch('https://api.github.com/orgs/anitab-org/repos');
      const jsonData = await response.json();
      const DATA = await Promise.all(jsonData.map(async ({ name }) => {
        repos.push(name);
        const issuesResponse = await fetch(`https://api.github.com/repos/anitab-org/${name}/issues`);
        const issuesJSON = await issuesResponse.json();
        const repoIssues = issuesJSON.map(this.normalizeIssue);
        return repoIssues.filter(issue => issue !== undefined);
      }))
      
      // DATA needs to be flat since it's an array of arrays
      this.setState({
        repos,
        DATA: DATA.flat(),
        isLoading:false,
      })
    } catch (error) {
      console.log(error);
    }
  }


  normalizeIssue = (issue) => {
    let flag = false;
    const issueNormalized = {
        id:issue.id.toString(),
        url:issue.html_url,
        title:issue.title,
        milestones:issue.milestones,
        comments:issue.comments,
        number:issue.number,
        assignees:issue.assignees,
        labels:[],
    };
    issue.labels.forEach(function(label){
        if(label.name === "First Timers Only") flag = true;
        issueNormalized.labels.push({
            id:label.id,
            name:label.name,
            color:label.color
        })
    })
    if(flag === true && issueNormalized !== null) return issueNormalized
  }

Upvotes: 1

Related Questions