zac
zac

Reputation: 4898

How I should dispatch the action to fetch the data using react components and redux?

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; 
    }
}

Upvotes: 0

Views: 1617

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281676

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)

Upvotes: 1

Related Questions