question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

componentWillReceiveProps not being called even though mapStateToProps returns different value

See original GitHub issue

I had initially posted this issue on the redux github here(https://github.com/reactjs/redux/issues/2317) but was advised to move it here.

Do you want to request a feature or report a bug?
bug

What is the current behavior? componentWillReceiveProps is not called even though mapStateToProps returns different values

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar. It’d be hard to create a minimal example here but I can show what’s happening in my code. I’m having problems getting componentWillReceiveProps to be called reliably in my code. The logging output below is writing out the calls to mapStateToProps, componentWillReceiveProps, and render and as you can see the final call that I would expect to happen isn’t happening even though mapStateToProps is returning state that would be different when using shallow compare.

Console Logging

detailsTabContainer.mapStateToProps {"drawerClosed":true}
detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:3(2)  detailsTabContainer.componentWillReceiveProps (isClosing, isSubmitting) false true
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:57 detailsTabContainer.render
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:3(2)  detailsTabContainer.componentWillReceiveProps (isClosing, isSubmitting) false true
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:57 detailsTabContainer.render
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(4) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(4) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":false}

code

import React from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {submit} from 'redux-form';
import { CANVAS_OBJECT_TYPES } from '../../../../../constants/canvasObjectTypes';
import * as icActions from '../../../../../state/actions/internalControl.action';
import DetailsTab from './detailsTab';

class DetailsTabContainer extends React.Component {

  //This is a hack. Should be done with a callback from the flyout after the flyout is fully open.
  componentDidMount() {
    console.log('detailsTabContainer.componentDidMount');

    if (this.props.content.isNew) {
      setTimeout(() => {
        this.refs && this.refs.controlId && this.refs.controlId.focus();
      }, 200);
    }
  }

  componentWillReceiveProps(nextProps) {
    const isClosing = this.props.drawerClosed && nextProps.drawerClosed === false;
    const isSubmitting = !this.props.drawerSubmitted && nextProps.drawerSubmitted === true;

    console.log('detailsTabContainer.componentWillReceiveProps (isClosing, isSubmitting)', isClosing, isSubmitting);

    if (isClosing || isSubmitting) {
      this.props.actions.submit(CANVAS_OBJECT_TYPES.Control);
    }
  }

  render() {
    console.log('detailsTabContainer.render');
    // TODO: Ryan - remove spreading out of props and moved to more typed approach
    return <DetailsTab {...this.props}/>;
  }
}

const mapStateToProps = state => {
  const props = {
    drawerClosed: state.drawerState && state.drawerState.drawer && state.drawerState.drawer.show,
    drawerSubmitted:(state.drawerState && state.drawerState.drawer && state.drawerState.drawer.submitted) || false
  };

  console.log('detailsTabContainer.mapStateToProps', JSON.stringify(props));

  return props;
};

const mapDispatchToProps = dispatch => ({
  actions: bindActionCreators({submit}, dispatch)
})


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

What is the expected behavior? That componentWillReceiveProps would be called after the last two calls to mapStateToProps as the result is different.

(2) detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":true,"drawerSubmitted":true}
detailsTabContainer.js:69 detailsTabContainer.mapStateToProps {"drawerClosed":false}

Which versions of Redux, and which browser and OS are affected by this issue? Did this work in previous versions of Redux?

    "react": "^15.3.2",
    "react-dom": "^15.3.2",
    "react-redux": "^5.0.3",
    "redux": "^3.6.0",

chrome Version 57.0.2987.110 (64-bit) mac seirra 10.12.3

Haven’t tried it in previous versions of Redux

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

2reactions
flqcommented, May 4, 2017

Hi there, what does “accidental mutation” mean? I am having a situation where componentWillReceiveProps is not been triggered even though the properties are changing.

0reactions
flqcommented, May 4, 2017

Oh that, yeah. No, I create a new state. Ive been using this stack a few times, with not too much trouble lately. My problem is not a lack of rendering (the render method is called), but that the props-receive hook for updating internal state is not called. If time permits I’ll try to produce a repro tomorrow.

Read more comments on GitHub >

github_iconTop Results From Across the Web

componentWillReceiveProps not being called if 2 different ...
Your connected component only need to pass down single state prop state.message (no dispatchProps and ownProps), as long as it remains unchanged ...
Read more >
How to not be deceived by Redux - Lohika
Therefore, we have to be very careful with mapStateToProps returned values. Do not connect all models – connect only a leaf of store...
Read more >
Connect: Extracting Data with mapStateToProps | React Redux
It does not matter if a mapStateToProps function is written using the ... is the entire Redux store state (the same value returned...
Read more >
componentWillReceiveProps is not called despite action and ...
Coding example for the question componentWillReceiveProps is not called despite ... const mapStateToProps = (state, ownProps) => { return { prescription ...
Read more >
Usage of Reselect in a React-Redux Application - Medium
After mapStateToProps() yields recalculated props, the new props are shallow compared to the old ones and if they differ, component gets rerendered. Again, ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found