Ahmed Saeed
Ahmed Saeed

Reputation: 645

Update component state to view data in Flatlist with Redux

I am using Redux to fetch data and add it to the store and after adding it i tried to view the result in a Flat List but the following error message appear in logger

enter image description here

and i searched for a while and i got the fact that i have to use conditions to prevent Flat List from rendering before data fetched and get added to the store, so i tried to assign my data list to my local component state with componentWillReceiveProps to force the component to rerender and view the list of data in Flat List but suddenly the same error appear although i already used conditions that make Flat List wait till data received and saved to store .

the data is looks like the following

enter image description here

homePage.js that contain Flat List

import React from 'react';
import { Text, View, ScrollView, TouchableOpacity, FlatList } from 'react- 
native';
import {Container, Header, Content, Item, Input, Button} from 'native-base';
import RPostCard from './reusablePostCard';
import FontAwesome5 from 'react-native-vector-icons/FontAwesome5';
import Foundation from 'react-native-vector-icons/Foundation';

class HomePage extends React.Component {
constructor(props){
    super(props);
    this.state = {
        postsData: []
    }
}

componentDidMount(){
    this.props.getNewsFeedPosts();
}

componentWillReceiveProps(nextProps){
    if (nextProps.postsData !== this.props.postData){
        this.setState({postsData: nextProps.postsData})
    }
}

render() {
    let { postsData, postsFetched } = this.props;
    return (
        <View style={styles.container}>
            <Header style={styles.header}>
                <View style={styles.messagesIconView}>
                    <TouchableOpacity onPress={() => this.props.navigation.navigate('Chat')}>
                        <FontAwesome5 name='comment' size={23} color='#ffffff'/>
                    </TouchableOpacity>
                </View>
                <View style={styles.telephoneIconView}>
                    <TouchableOpacity>
                        <Foundation name='telephone' size={25} color='#ffffff'/>
                    </TouchableOpacity>
                </View>
                <Content style={styles.searchContent}>
                    <Item style={styles.searchItem}>
                        <Input placeholder='ابحث هنا' placeholderTextColor='#ffffff' style={styles.inputValueStyle}/>
                        <FontAwesome5 name='search' size={15} color='#ffffff' style={styles.searchIconStyle}/>
                    </Item>
                </Content>
            </Header>
            {(this.state.postsData.length === 0) ?
                null
                :
                <ScrollView>
                    <FlatList
                        data={this.state.postsData}
                        renderItem={({postData}) => (<Text>{postData.title}</Text>)}
                    />
                </ScrollView>
            }
        </View>
    );
}
}

HomePage.defaultProps = {
}

export default HomePage;

Home Container which contain mapstatetoprops & mapActionCreators

import {connect} from "react-redux";
import HomePage from "../../components/HomeScreens/HomePage";
import {
    getNewsFeedPosts
} from "../../modules/Home";

const mapStateToProps = (state) =>({
    postsData: state.Home.posts,
    postsFetched: state.Home.postsFetched,
});

const mapActionCreators = {
    getNewsFeedPosts
};
export default connect(mapStateToProps, mapActionCreators)(HomePage);

Action Handler function that componentdidmount() call in HomePage.js

function handleNewsFeedPosts(state, action){
const postsData = action.payload.data.posts;
const likesNo = action.payload.data.likes;
const commentsNo = action.payload.data.comments;
const post = {};
var posts = [];
var postsIds = [];
var imageLink = "http://192.168.1.117:3000/image/";
var month_ar = '';
var month_en = '';
var oldPostsState = [];
var oldPostsIdsState =[];
for (i = 0; i < postsData.length; i++) {
    //filter description from <p> </p> tags
    const description = postsData[i].description;
    const filteredDescription = description.replace(/<[^>]*>/g, '');

    //filter date and time from  '-' and split date and time converting it to arabic
    const created_at = postsData[i].created_at.replace(/-/g, ' ');
    created_at = postsData[i].created_at.replace(/:/g, ' ');
    const created_at_filter = postsData[i].created_at.split(' ');
    const date = created_at_filter[0].split('-');
    const month = parseInt(date[1]);

    switch (month) {
        case 1:
            month_en = " January ";
            month_ar = " يناير ";
            break;
        case 2:
            month_en = " February ";
            month_ar = " فبراير ";
            break;
        case 3:
            month_en = " March ";
            month_ar = " مارس ";
            break;
        case 4:
            month_en = " April ";
            month_ar = " ابريل ";
            break;
        case 5:
            month_en = " May ";
            month_ar = " مايو ";
            break;
        case 6:
            month_en = " June ";
            month_ar = " يونيو ";
            break;
        case 7:
            month_en = " July ";
            month_ar = " يوليو ";
            break;
        case 8:
            month_en = " August ";
            month_ar = " أغسطس ";
            break;
        case 9:
            month_en = "September";
            month_ar = "سبتمبر";
            break;
        case 10:
            month_en = " October ";
            month_ar = " أكتوبر ";
            break;
        case 11:
            month_en = " November ";
            month_ar = " نوفمبر ";
            break;
        case 12:
            month_en = " December ";
            month_ar = " ديسمبر ";
            break;
    }

    const created_at_ar = created_at.replace(/\d/g, d =>  '٠١٢٣٤٥٦٧٨٩'[d]);

    //Ready English format
    const created_at_en = setCharAt(created_at, 4, month_en);

    //Ready Arabic format
    created_at_ar = setCharAt(created_at_ar, 4, month_ar);

    //Link post image name with the complete require link
    const image = postsData[i].image;
    imageLink = imageLink.substr(0,imageLink.length) + image;


    const post = {
        id: postsData[i].id,
        title: postsData[i].title,
        description: filteredDescription,
        type: postsData[i].type,
        category_id: postsData[i].category_id,
        image: imageLink,
        created_at_ar: created_at_ar,
        created_at_en: created_at_en,
        likesNo: likesNo[i],
        commentsNo: commentsNo[i],
    }

    //push posts data to one array 
    posts.push(post);

    //collect posts id to send it back and get a new array of posts
    postsIds.push(post.id);

    }
    if (fetchDataCounter == 0){
        var newPostsState = posts;
        var newPostsIdsState = postsIds;
    }
    else{
        //merge old posts state array with new one
        oldPostsState = action.posts;
        var newPostsState = oldPostsState.concat(posts);

        //merge old posts ids state array with new one
        oldPostsIdsState = action.postsIds;
        var newPostsIdsState = oldPostsIdsState.concat(postsIds);
    }

    fetchDataCounter ++;
    return update(state, {
        posts:{
            $set: newPostsState
        },
        postsIds:{
            $set: newPostsIdsState
        },
        postsFetched: {
            $set: true
        }
    });
}



const ACTION_HANDLER = {
    NEWS_FEED_POSTS:handleNewsFeedPosts
}
const initialState = {
    posts:[],
    postsFetched: false,
    postsIds:{},
    data: 'blablabla...'
}

Upvotes: 0

Views: 1651

Answers (2)

Pravin Ghorle
Pravin Ghorle

Reputation: 690

<FlatList
    style = {styles.myAddressList}
    data = {useSelector((state) => state.address.address)}
    renderItem = {renderItem}
    keyExtractor = {item => item._id}
    ListEmptyComponent = {EmptyList}
    ItemSeparatorComponent={SeparatorWhite}
    
    />

Upvotes: 0

Fabrizio Rizzonelli
Fabrizio Rizzonelli

Reputation: 429

First of all, FlatList scrolls by itself, you don't need to wrap it in a ScrollView.

Also, I think the problem is here

renderItem={({postData}) => (<Text>{postData.title}</Text>)}

renderItem is a function which an object parameter with the following structure:

export interface ListRenderItemInfo<ItemT> {

   item: ItemT;

   index: number;

   separators: {
       highlight: () => void;
       unhighlight: () => void;
       updateProps: (select: "leading" | "trailing", newProps: any) => void;
   };
}

You need to extract the item object in your renderItem function like this

renderItem={({item}) => (<Text>{item.title}</Text>)}

Then it'd work :)

Upvotes: 1

Related Questions