Ivan Bogolyubskiy
Ivan Bogolyubskiy

Reputation: 86

React twice mount component, but on second time doesn't receive props

import React, {Component} from 'react';
import { Link } from 'react-router';


class AsideNav extends Component{
    constructor(props, context) {
    super(props, context);

    this.state = {
        navigation: ''
    };
}

componentWillMount(){
    console.log(this.props.data.navigation); // data from parent received
    this.setState({
        navigation:  this.props.data.navigation.map(function(el, index){
            return(
                <Link key={index} className={"aside-nav__link " + (el.modifier ? ("aside-nav__link" + el.modifier) : '')} to={el.url}>{el.name}</Link>
            )
        })
    })
}



render() {
    console.log(this.state.navigation); // JSX for navigation is ready
    return (
        <nav className="aside-nav">
            <span className="aside-nav__title" >Категории</span>
                {this.state.navigation}
        </nav>
    );
}

}

export default AsideNav

After (seemingly) successful implementation of code it displays me an empty block and

Uncaught TypeError: Cannot read property 'navigation' of undefined at AsideNav.componentWillMount...

Upvotes: 1

Views: 3812

Answers (3)

Ivan Bogolyubskiy
Ivan Bogolyubskiy

Reputation: 86

import React from 'react';
import {render} from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';


import App from './app';
import PageDashboard from './page-templates/page-dashboard';
import PageRating from './page-templates/page-rating';


import './styles/css/style.css';

//render(<PageDashboard />, document.querySelector('.main-wrapper')); - before

render(  
    <Router history={browserHistory}>
        //<Route path="/public/" component={App} />  - before
        <Route path="/public/" component={PageDashboard} />  // -  now
        <Route path="/public/rating" component={PageRating} />
    </Router>, document.querySelector('.main-wrapper')
);

A problem located in root file 'main.js'. I accidentally have mounted two components with common children.

Upvotes: 0

Mayank Shukla
Mayank Shukla

Reputation: 104459

Changes:

1. Never store the ui items in state variable, always store data only and then generate the ui elements dynamically.

2. Use componentWillReceiveProps method, it will get called if you do any changes in props values in parent component, update the state value of child component at that time.

3. Since you just want to create the items from props data, directly use props, instead of storing anything.

Write it like this:

import React, {Component} from 'react';
import { Link } from 'react-router';


class AsideNav extends Component{
    constructor(props, context) {
        super(props, context);

        this.state = { };
    }

    renderLinks(){
        let data = this.props.data;
        return data && Array.isArray(data.navigation) && data.navigation.map((el, index) => {
            return(
                <Link 
                    key={index} 
                    className={"aside-nav__link " + (el.modifier ? ("aside-nav__link" + el.modifier) : '')} 
                    to={el.url}
                >
                    {el.name}
                </Link>
            )
        })
    }



    render() {
        console.log(this.props.data)
        return (
            <nav className="aside-nav">
                <span className="aside-nav__title" >Категории</span>
                {this.renderLinks()}
            </nav>
        );
    }

}

Upvotes: 1

Ved
Ved

Reputation: 12103

se componentWillReceiveProps(newProps) to get props second time as constructor and componentDidMount methods get executed only once. And also add check if data available or not.

import React, {Component} from 'react';
import { Link } from 'react-router';


class AsideNav extends Component{
    constructor(props, context) {
    super(props, context);

    this.state = {
        navigation: ''
    };
}
componentWillReceiveProps(newProps)
{
console.log(newProps.data.navigation); // data from parent received
    this.setState({
        navigation:  newProps.data &&newProps.data.navigation.map(function(el, index){
            return(
                <Link key={index} className={"aside-nav__link " + (el.modifier ? ("aside-nav__link" + el.modifier) : '')} to={el.url}>{el.name}</Link>
            )
        })
    })
}

componentWillMount(){
    console.log(this.props.data.navigation); // data from parent received
    this.setState({
        navigation:  this.props.data && this.props.data.navigation.map(function(el, index){
            return(
                <Link key={index} className={"aside-nav__link " + (el.modifier ? ("aside-nav__link" + el.modifier) : '')} to={el.url}>{el.name}</Link>
            )
        })
    })
}



render() {
    console.log(this.state.navigation); // JSX for navigation is ready
    return (
        <nav className="aside-nav">
            <span className="aside-nav__title" >Категории</span>
                {this.state.navigation}
        </nav>
    );
}

}

export default AsideNav

Upvotes: 0

Related Questions