简体   繁体   中英

React doesn't recognize state change in reducer

I have a component that makes an API call and then updates the state through a reducer. The problem is, this doesn't work so well cause the data don't get updated in the component, it's like the react didn't notice a state change a never re-rendered the component, but I'm not sure if that's the real issue here. So the component looks like this:

class MyComponent extends Component {
  componentDidMount() {
    // ajax call
    this.props.loadData(1);
  }

  render() {
    return (
      <Grid>
        <MySecondComponent
          currentData={this.props.currentData}

        />
      </Grid>
    );
  }
}

const mapStateToProps = state => ({
  reducer state.myReducer,
  currentData: state.myReducer.currentData
});

const mapDispatchToProps = dispatch => {
  return {
    loadData: () => {
      HttpClient.getData(id, (data) => {
        dispatch(
          action_loadCurrentData(
            data
          )
        );
      });
    },
  };
};

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

I am doing 2 things here: issuing an API call as soon as component is mounted, and then after data is fetched, dispatching action_loadCurrentData

This action looks like this:

//Action

export function action_loadCurrentData(
  data
) {
  return {
    type: 'LOAD_CURRENT_DATA',
    payload: {
      currentData: data,
    }
  };
}

and the reducer:

//Reducer

const defaultState = {

};

const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case 'LOAD_CURRENT_DATA':
      state = {
        ...state,
        currentData: {
          myData: {
            ...state.currentData.myData,
             0: action.payload.currentData
          }
        }
      };
    }
};

export default myReducer;

So the issue here is that the this.props.currentData that I'm passing to MySecondComponent will end up empty, as if I didn't set the data at all. However, If I stop the execution in the debugger and give it a few seconds, the data will be populated correctly, so I'm not sure what I'm doing wrong here?

Don't reassign state, return the newly created object instead

 const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case 'LOAD_CURRENT_DATA':
      return {
        ...state,
        currentData: {
          myData: {
            ...state.currentData.myData,
             0: action.payload.currentData
          }
        }
      };
    }
};

Your reducer needs to return the new state object, which needs to be a different instance from the previous state to trigger components update.

According to redux documentation :

The reducer is a pure function that takes the previous state and an action, and returns the next state .

And

Things you should never do inside a reducer:

  • Mutate its arguments ;
  • Perform side effects like API calls and routing transitions;
  • Call non-pure functions, eg Date.now() or Math.random().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM