Search code examples
reactjsreduxreact-redux

New posts on my app are not showing but the old posts are. React


I recently added redux to my social media app. The old posts(The ones that were there before I added redux) are getting rendered correctly but when I try to add a new post it just shows a blank card. I checked the redux store and everything and the data is getting stored correctly. This is the redux state before I add a new post. You can see the old posts(The ones that were there before I added redux to my project)

This is after I add a new post. The data is correctly added to the redux store but all it shows is a blank card on the webpage

This is the code responsible for rendering the posts.

class PostComment extends Component{

state={
    showNewPost: false
}

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

DeleteCommentHandler = (index) => {
   this.props.onDeletePost(index);
}

ShowFunction = () => {
    this.setState({showNewPost: !this.state.showNewPost})
}

render() {
    let cardData = <center> <Spinner/></center>

    if(!this.props.loading){
   cardData = <div className="posts">  
   {/*add font awesome search icon*/}   
   <div className="topSection">
       <input type="text" className="Searchbar" placeholder="Search for people, topics or keywords..."/>
       <Button className="btn btn-primary">Search</Button>
       <NewPost/>
       </div>

{this.props.data.reverse().map((res) => (    
        <div>
                   <Card
                   key={res.id}
                   className="Cards"
                   >

                  <Card.Body
                  className="container">
                       <h6>
                       @ANONYMOUS
                        </h6>
                       <Card.Text>
                        {res.Comment} 
                       </Card.Text>
                        
                        <div>
                            <center>
                        <img src={res.ImageUrl} width = "680px" height="390px" />
                            </center>
                            </div>
                 

                <br/>
                 <Button className="btn btn-danger" 
                 style={{float:"right", width:"35px", height:"35px", borderRadius:"5px"}}
                 onClick={() => this.DeleteCommentHandler(res.id)}>
                     
                     <center>
                     <FontAwesomeIcon icon={faTrash} style={{width:"11px"}}/>
                     </center>

                     </Button> 
                   </Card.Body>
                   <Card.Footer style={{position:"relative", marginTop:"20px"}}>
                       {res.Date}
                   </Card.Footer>
                   </Card>                                
                   
           </div>
       )
)}
</div>
}

return(

<div> 
    {cardData}
 </div>

);
}
}

const mapStateToProps = state => {
    return {
        data: state.Data,
        loading: state.loading
    };
};
const mapDispatchToProps = dispatch => {
    return {
        onFetchPosts: () => dispatch(actions.FetchPost()),
        onDeletePost: (postId) => dispatch(actions.DeletePost(postId))
    };
};

export default connect(mapStateToProps, mapDispatchToProps)(PostComment);

This is the action.js file

import axios from '../../axios-comments';
import * as actionTypes from './actionTypes';


export const NewPostSuccess = (id, postData) => {
    return {
        type: actionTypes.New_Post_Success,
        payload: {
            data: postData,
            id: id
        }
    }
}

export const NewPostError = (error) => {
    return {
        type: actionTypes.New_Post_Error,
        error: error
    }
}


export const NewPost = (postData) => {
  
          return (dispatch) => {
           axios.post('/Data.json', postData)
           .then(response => {
               console.log(response.data);
               dispatch(NewPostSuccess(response.data.name, postData));
           })
           .catch(error => {
               dispatch(NewPostError(error));
           })
          }
  }

  
  export const DeletePostSuccess = (id) => {
    return {
        type: actionTypes.Delete_Post_Success,
        index: id
    }
}


  export const DeletePost = (index) => {
      
        return (dispatch) => {
    axios.delete('/Data/'+ index + '.json')
    .then(response => {
        console.log(response.data);
        dispatch(DeletePostSuccess(index))   
    })
            }
  }


  export const FetchPostStart = () => {
    return {
        type: actionTypes.Fetch_Post_Start
    };
};

  export const FetchPostSuccess = (fetchedData) => {
    return {
        type: actionTypes.Fetch_Post_Success,
        payload: fetchedData
    }
}

export const FetchPostError = (error) => {
    return {
        type: actionTypes.Fetch_Post_Error,
        error: error
    }
}
  
export const FetchPost = () => {
    return dispatch => {
        dispatch(FetchPostStart());
        axios.get('/Data.json')
        .then(response => {
           const fetchedData = [];
    
           for(let key in response.data){
                   fetchedData.push({
                   ...response.data[key],
                   id: key
               });
           }
           dispatch(FetchPostSuccess(fetchedData));
        })
    
        .catch(error => {
            dispatch(FetchPostError(error));
        });
    }
}

This is the reducer function

import * as actionTypes from '../actions/actionTypes';

const initialState = {
    Data: [],
    loading: false
}

const reducer = (state = initialState, action) => { 
    switch(action.type){
     
        case actionTypes.New_Post_Error: 
        return {
          ...state,
          loading:false
        }

        case actionTypes.New_Post_Success: 
        return {
         ...state,
         loading: false,
         Data: [...state.Data, action.payload.data]
        }

        case actionTypes.Delete_Post_Success:
          const selectedComment = state.Data.filter(res => res.id !== action.index);  
        return {
            ...state,
            loading: false,
            Data: selectedComment
          }

        case actionTypes.Fetch_Post_Start: 
        return {
            ...state,
            loading:true
          }

        case actionTypes.Fetch_Post_Error: 
        return {
            ...state,
            loading:false
          }
  
          case actionTypes.Fetch_Post_Success: 
          return {
           ...state,
           loading: false,
           Data: action.payload
          }

     default: return state;
 }
}

export default reducer;

Thank you so much


Solution

  • From what I can tell, yes, you populate state.Data, but notice in the old objects that your property keys are PascalCased instead of camelCased like the newly added post object.

    enter image description here vs enter image description here

    In your code you are mapping res.Comment and res.ImageUrl!

    While I highly encourage you to adopt a more standard pascalCased naming convention (likely starting from the source in your JSON data!!), you can update the new post success reducer case to maintain the state invariant.

    case actionTypes.New_Post_Success: 
      const { comment: Comment, imageUrl: ImageUrl } = action.payload.data;
      return {
        ...state,
        loading: false,
        Data: [
          ...state.Data,
          { Comment, ImageUrl },
        ],
      }