React is not mapping through an array. I can see an array in the console log like this.Shows loading instead of mapping through the array.

enter image description here

The array comes from redux reducer. I think im doing everything right according to redux.

reducer/posts.js

import {GET_POSTS, '../actions/';

const initialState = {
    post: [],
    postError: null,
    posts:[]
}

export default (state = initialState, action) => {
    switch (action.type) {
        case GET_POSTS:
            // console.log(action.data)
            return {...state, posts: action.data}
    default:
            return state

Could it be an async lifecycle method issue ?

actions/index.js

export const GetPosts = () => {
    return (dispatch, getState) => {
        return Axios.get('/api/posts/myPosts')
            .then( (res) => {
                 const data = [...res.data]

                 console.log(data); // logs data and i can see an array 

                 dispatch({type: GET_POSTS, data })
             })

    }
}

Posts.js

import React, { Component } from 'react';
import PostList from './PostList';
import Axios from '../Axios';
import {connect} from 'react-redux';
import { withRouter, Redirect} from 'react-router-dom';
import {DeletePost, GetPosts} from '../actions/';

const Styles = {
    myPaper:{
      margin: '20px 0px',
      padding:'20px'
    }
    , 
    wrapper:{
      padding:'0px 60px'
    }
}
class Posts extends Component {


  constructor(props){
    super(props);

    this.state = {
      posts: [],
      loading: true,
    }
  }


  componentWillMount(){
    this.props.GetPosts();
    const reduxPosts = this.props.myPosts;
    const ourPosts = reduxPosts  
    console.log(reduxPosts); // shows posts line 35
  }

  onDelete = (id) => {
    Axios.post(`/api/posts/delete/${id}`);
    this.setState({
      posts: this.state.posts.filter(post => post.id !== id)
    })
  }


  render() {
    const {loading} = this.state;
    const { myPosts} = this.props
    if (!this.props.isAuthenticated) {
      return (<Redirect to='/signIn' />);
    }
    if(loading){
      return "loading..."
    }
    return (
      <div className="App" style={Styles.wrapper}>
        <h1> Posts </h1>
        {/* doesn't map posts instead shows loading */}
        <PostList posts={myPosts}/>
      </div>
    );
  }
}
const mapStateToProps = (state) => ({
  isAuthenticated: state.user.isAuthenticated,
  myPosts: state.post.posts
})
const mapDispatchToProps = (dispatch, state) => ({
  // newPost: (post) => dispatch(newPost(post)),
  // DeletePost: (id) => dispatch( DeletePost(id))
  GetPosts: () => dispatch( GetPosts())
});
export default withRouter(connect(mapStateToProps,mapDispatchToProps)(Posts));

PostList.js

import React from 'react';
import Paper from '@material-ui/core/Paper';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import moment from 'moment';
import {connect} from 'react-redux';
import {DeletePost} from '../actions/';
const Styles = {
  myPaper:{
    margin: '20px 0px',
    padding:'20px'
  }
}
const PostList = ({ DeletePost, posts}) =>  {
  return(
    <div>
    {posts.map( (post, i) => (
      <Paper key={i} style={Styles.myPaper}>
        <Typography  variant="h6" component="h3">
        {post.title}  
        </Typography>
        <Typography component="p">
          {post.post_content}
          <h5> by: {post.username}</h5>
          <h5> {moment(post.createdAt).calendar()}</h5>
        </Typography>
        <Button 
          variant="outlined" 
          color="primary" 
          type="submit"
          onClick={() => DeletePost(post.id)}>
          Remove
        </Button>
      </Paper>
     ))}
  </div>
  )
  };
export default PostList;

1 Answers

1
jsdeveloper On Best Solutions

There doesn't seem to be anywhere in your code where you set loading to false when the getPosts function has resolved - so your app will always return the "loading..." string. Try something like this (assuming GetPosts returns a promise):

  async componentWillMount(){
    await this.props.GetPosts();
    this.setState({ loading: false })
    const reduxPosts = this.props.myPosts;  
    console.log(reduxPosts); // shows posts line 35
  }