Search code examples
javascriptreactjsreduxredux-saga

React component not updating on redux state update


I am using react, redux and redux-saga for my project. While fetching a list of users using Redux-saga, I can see that my redux store is getting updated (I can see it from the redux dev tool), But in the component , props are not changing.

I am using a button to get the list of users. And the users are showing up in that component only.

App.js

import React, { Component } from 'react';
import { connect } from "react-redux";
import './App.css';
import { fetchUsers } from "./actions";
import { Row, Col, ListGroup, ListGroupItem } from "reactstrap";

class App extends Component {

  // eslint-disable-next-line no-useless-constructor
  constructor(props){
    super(props);
  }

  render() {
    console.log("in render func");
    console.log(this.props);
    return (
      <div className="App">
        <h2>Redux Saga App</h2>
        <Row>
          <Col sm={6}>

            {this.props.userList?this.props.userList.map((user)=>(
              user.first_name + user.last_name
            )) : ''}
          </Col>
        </Row>
        <button onClick={this.props.getUserList}>Click to get the users</button>
      </div>
    );
  }
}

const mapStateToProps = (state)=>{
  console.log("in map statetpprop");
  //console.log(state.userList);
  return {userList:state.userList}
}

const mapDispatchToProps = (dispatch)=>{
  return {getUserList :() => {dispatch(fetchUsers())}}
}


App = connect(mapStateToProps,mapDispatchToProps)(App);

export default App;

action.js

export function fetchUsers(){
    return {
        type:'FETCH_USERS',

    }
}

reducer.js

const initialState = {
    userList:[]
}
export function userReducer(state=initialState,action){
    switch(action.type){
        case 'ADD_USER':
            return Object.assign(state,{
                user:action.data
            })
        case 'SET_USERS':
            return Object.assign(state, {userList : action.data});
        default:
            return state;
    }
}

saga.js

import {call, put , takeEvery , takeLatest } from 'redux-saga/effects';
import axios from 'axios';
import { setUsers } from "./actions";

export function fetchUsersFunc(userId){

    return axios.get('https://reqres.in/api/users');
}

function* fetchUsers(action){
    const users = yield call(fetchUsersFunc);
    console.log("in fetch users");

    if(users.data.data){
        const userList = users.data.data;
        console.log(userList);
        console.log(userList[0].first_name)
        yield put(setUsers(userList));
    }

}


export function* rootSaga(){
    yield [
        takeLatest('FETCH_USERS',fetchUsers)

    ];
}

Thanks for the help!


Solution

  • If you use Object.assign and you want to make a new copy of the state, you need to make the target object to a new empty object instead of what you are currently doing (it mutates the state object, which makes the react unable to re-render). (You can see See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign for more information on Object.assign) For example:

    // copy previous state and new updates to a new empty object  
    return Object.assign({}, state, {userList : action.data}); 
    

    I would recommend using the spread operator instead of Object.assign though:

    return {...state, userList : action.data}