0

I am fetching data using axios and then map state to props with redux but I have a problem. If I dispatch the action in componentDidUpdate() the action execute indefinitely and if I used the constructor(props) I get undefined value for props I tried also componentDidMount but I get undefined value for probs. Is there a way to dispatch the action using react components ?

I get the correct data from state in the second render.

import React, { Component } from 'react' import {connect} from 'react-redux' import { getUserPosts } from '../../actions' class UserPosts extends Component { //UNSAFE_componentWillMount() { //} constructor(props) { super(props); console.log(props); } componentDidUpdate() { //this.props.dispatch(getUserPosts(this.props.user_reducer.login?.user._id)); } showUserPosts = (user) => ( Array.isArray(user.userPosts) ? user.userPosts.map((item, i) => ( <tr key={i}> <td>{i}</td> <td>author</td> <td>date</td> </tr> )) : null ) render() { let user = this.props.user_reducer; //console.log(user.userPosts); return ( <div> <div className="user_posts"> <h4>Your reviews:</h4> <table> <thead> <tr> <th>Name</th> <th>Author</th> <th>Date</th> </tr> </thead> <tbody> {this.showUserPosts(user)} </tbody> </table> </div> </div> ) } } function mapStateToProps(state) { //console.log(state); return { user_reducer: state.user_reducer } } export default connect(mapStateToProps)(UserPosts) 

action:

export function getUserPosts(userId) { const req = axios.get(`/api/user_posts?user=${userId}`) .then(res => res.data); return { type: 'GET_USER_POSTS', payload: req } } 

reducer:

export default function(state = {}, action) { switch(action.type) { case 'USER_LOGIN': return {...state, login: action.payload} case 'USER_AUTH': return {...state, login: action.payload} case 'GET_USER_POSTS': return {...state, userPosts: action.payload} default: return state; } } 
7
  • did you used dispatcher in action.js Commented May 20, 2020 at 19:06
  • no I use it in the component above Commented May 20, 2020 at 19:09
  • Can we see your store/reducer setup? Also, did you wrap your application in Provider? Commented May 20, 2020 at 19:09
  • Can you get the user id from anywhere else like router params? Otherwise maybe restructure things to not pass an id and have the store request the user specific data based on a user id set via a previous dispatch in the background then map state to props to this new property such as userDetail. Commented May 20, 2020 at 19:10
  • 1
    I don't mean from the store, but from other sources. Are you using react-router-dom or something like that where you can get the _id from the url params for example? The _id property you are is nested very deeply. It may not be available until after the component has mounted. Commented May 20, 2020 at 19:23

1 Answer 1

1

The correct place to dispatch an action is in componentDidMount. However since your data fetch is async, you must maintain a loading state in your reducer till your data is fetched

export default function(state = {isPostLoading: true}, action) { switch(action.type) { case 'USER_LOGIN': return {...state, login: action.payload} case 'USER_AUTH': return {...state, login: action.payload} case 'GET_USER_POSTS': return {...state, userPosts: action.payload, isPostLoading: false} default: return state; } } 

class UserPosts extends Component { constructor(props) { super(props); console.log(props); } componentDidMount() { this.props.dispatch( getUserPosts(this.props.user_reducer.login?.user._id) ); } componentDidUpdate(prevProps) { if(this.props.user_reducer.login?.user._id !== prevProps.user_reducer.login?.user._id) { this.props.dispatch(getUserPosts(this.props.user_reducer.login?.user._id)); } } showUserPosts = (user) => ( Array.isArray(user.userPosts) ? user.userPosts.map((item, i) => ( <tr key={i}> <td>{i}</td> <td>author</td> <td>date</td> </tr> )) : null ) render() { let user = this.props.user_reducer; if(user.isPostLoading) { return <div>Loading....</div> } return ( <div> <div className="user_posts"> <h4>Your reviews:</h4> <table> <thead> <tr> <th>Name</th> <th>Author</th> <th>Date</th> </tr> </thead> <tbody> {this.showUserPosts(user)} </tbody> </table> </div> </div> ) } } function mapStateToProps(state) { return { user_reducer: state.user_reducer } } export default connect(mapStateToProps)(UserPosts) 
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks but first render I dont get the data, I get it in second render. user_reducer prop in componentDidMount is empty . old code was using componentWillMount which not used now
Is the login value true on initial render
yes the login value was false, it seems you know now I am following a tutorials :) it work now thanks
Seems like you would need to use of combination of componentDidMount and componentDidUpdate since your login was false
Glad to have helped
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.