Why might componentDidMount() not work in a React container if I try to call a component again?

There is a list of links like

 <Link key={element.name} to={'elements/:element'}} /> 

from the link, I take the name of this element and pass it to the props ElementDetail container (conditionally)

 <ElementDetail name={:element} /> 

I already use the name from props inside the componentDidMount() method:

 @connect( state => ({ element: state.element }), dispatch => ({elementActions: bindActionCreators(elementActions, dispatch)}) ) export default class ElementDetail extends React.Component { componentDidMount() { console.log('>>> CDM') let { getProperties } = this.props.elementActions; getProperties(this.props.name) } render() { let { properties, isLoading } = this.props.element; let propertyGroups = properties['properties']; console.log('>>> RENDER') return <div /> 

When you first mount the component, the code works as needed.

However, when I try to call the component c with other data via Link, I only get an update of the address in the browser and the change of props.name . Only the code inside render () works, as I see from the console output. Where do I make a mistake?

    2 answers 2

    Without the full code it is difficult to say, but it is obvious that the component is not initialized a second time, but is updated. This can be checked in componentWillReceiveProps() . If componentWillReceiveProps() is called a second time, rather than componentDidMount() , then you need to work with componentWillReceiveProps() .

    The fact is that when sending new props component is not reinitialized, but only accepts new props .

    componentDidMount () is invoked immediately after a component is mounted

    componentWillReceiveProps () is invoked before a mounted component receives new props

    • Yes, you are right the second time componentWillReceiveProps is called. If correctly understood, the componentWillReceiveProps method is not called to initialize the render. I use componentDidMount () to execute getProperties (this.props.name), in which the request to the server is executed. And will it correctly execute asynchronous code in the componentWillReceiveProps method? For such actions, as far as I know, componentDidMount () is used. - while1pass
    • If you need to update state when receiving new props, then componentDidMount is the only right place for that. - Nick

    Found two solutions.

    The first is the added key attribute on the component, the key changes (I take it from the routing) and this forces the reactant to remount the component

     let name = this.props.params.element; ... <ElementDetail name={name} key={name} /> 

    Changing the key causes ComponentDidMount () each time.

     @connect( state => ({ element: state.element }), dispatch => ({elementActions: bindActionCreators(elementActions, dispatch)}) ) export default class ElementDetail extends React.Component { componentDidMount() { let { getProperties } = this.props.elementActions; getProperties(this.props.name) } ... 

    The second is using componentWillReceiveProps () (thanks to Nick for the tip)

     let name = this.props.params.element; ... <ElementDetail name={name} /> 

    And in the component itself

     @connect( state => ({ element: state.element }), dispatch => ({elementActions: bindActionCreators(elementActions, dispatch)}) ) export default class ElementDetail extends React.Component { componentWillReceiveProps(nextProps) { if (nextProps.name !== this.props.name) { let { getProperties } = this.props.elementActions; getProperties(nextProps.name) } } componentDidMount() { let { getProperties } = this.props.elementActions; getProperties(this.props.name) } ... 

    but in the second method there is more code and it is duplicated.

    If someone gives their explanations and comments, it will be excellent

    • one
      In this case, more code is better than initializing the component each time. React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state. . And so as not to duplicate the code let { getProperties } = this.props.elementActions; getProperties(this.props.name) let { getProperties } = this.props.elementActions; getProperties(this.props.name) can be rendered into a separate function - Nick