Andra
Andra

Reputation: 71

Async api fetch with redux thunk

I'm having trouble fetching a list of users from an api. I think issue might be in my mapDispatchToProps function but I'm not sure. Everything else seems fine to me. I'm new to redux and I'm kinda having a hard time wrapping my head around it so any help is appreciated

The list with the users would ideally be displayed as soon as the component mounts. I did the same thing without redux store and it was working just fine, I'm just not really sure how to integrate redux

Actions

export const startLoading = () => {
    return {
        type: START_LOADING
    }
}
export const updateUserData = payload => {
    return {
        type: UPDATE_USER_DATA,
        payload
    }
}
export const updateUserError = payload => {
    return {
        type: UPDATE_USER_ERROR,
        payload: payload
    }
}

export function fetchUsers() {
    return dispatch => {
        dispatch(startLoading());
        fetch('https://jsonplaceholder.typicode.com/users')
            .then(res => res.json())
            .then(data => {
                data = data.filter(user => user.id < 4);
                data.forEach(user => {
                    user.isGoldClient = false;
                    user.salary = '4000';
                    user.photo = userThumbnail;
                })
                .then(data => {
                    dispatch(updateUserData(data));
                }).catch(error => {
                    dispatch(updateUserError(error));
                })
            });
    };
};

Reducers

const initialState = {
    loading: false,
    users: [],
    error: null
};

export function userReducer(state=initialState, action){
    switch(action.type){
        case START_LOADING:
            return {
                ...state,
                loading: true
            }
        case UPDATE_USER_DATA:
            return {
                ...state,
                loading: false,
                users: action.payload,
                error: null
            }
        case UPDATE_USER_ERROR:
            return {
                ...state,
                error: action.payload,
                loading: false,
                users: []
            };
        default:
            return state;
    };
};

Component

class Home extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
        users: [],
        usersAreDisplayed: true
        };
    }
    componentDidMount() {
        fetchUsers();
    }
     
    render(){
        return (
             <UserList users={this.state.users} /> 
        )
    }
}

function mapStateToProps(state){
    return { users: state.users }
}

function mapDispatchToProps(dispatch){
    return {
        fetchUsers: payload => dispatch(updateUserData(payload)),
    }
}

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

Upvotes: 0

Views: 682

Answers (2)

gdh
gdh

Reputation: 13682

  1. Looks like you are not calling the actual fetchUsers at all.

Change the component code like this

function mapStateToProps(state){
  return { users: state.users }
}

// remove this function
// function mapDispatchToProps(dispatch){
//   return {
//       fetchUsers: payload => dispatch(updateUserData(payload)),
//   }
// }

export default connect(mapStateToProps, {fetchUsers})(Home); //<---- destructure it here. Also import the function (action)

1a. fetchUsers function needs to be accessed using this.props

    componentDidMount() {
        this.props.fetchUsers();
    }
  1. There is an extra then block after forEach. Remove it.
export function fetchUsers() {
  return (dispatch) => {
    dispatch(startLoading());
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((res) => res.json())
      .then((data) => {
        data = data.filter((user) => user.id < 4);
        data.forEach((user) => {
          user.isGoldClient = false;
          user.salary = "4000";
          user.photo = userThumbnail;
        });
        dispatch(updateUserData(data)); // <------ no extra .then is required
      })
      .catch((error) => {
        dispatch(updateUserError(error));
      });
  };
}
  1. Also <UserList users={this.state.users} /> needs to be <UserList users={this.props.users} /> As already mentioned by @Nsevens

Upvotes: 2

nsevens
nsevens

Reputation: 2835

You are mapping redux state into your component's props.

So you should load the users from the component's props and not it's state:

    render(){
        return (
             <UserList users={this.props.users} /> 
        )
    }

Upvotes: 1

Related Questions