7

I'm trying to pass props from a parent component to a child component and even though its getting called twice (dunno why, componentDidMount should get called only once) the props seem to be empty.

Parent component:

class Members extends Component{
    constructor(props){
        super(props);
        this.state = {
            interests: []
        }
    }

    componentDidMount(){
        fetch(interestUrl, {
            method: 'GET',
            headers: {
              "Content-Type": "application/json",
              "Authorization": this.props.authToken
            }
        })
        .then((response) => response.json())
        .then((json) => {this.setState({interests: json})})
        .catch(error => {console.log("Error: " + error)})
    };

    render(){
        return(
            <div className="Members-body">
                <div className="Menu-sidebar">
                    <Menu interestList = {this.state.interests}/>
                </div>
                <div className="Main-container">
                    <Main/>
                </div>
            </div>
        )
    }

}
export default Members;

Child component:

class Menu extends Component {
    constructor(props){
        super(props);
    }

    componentDidMount(){
        console.log("interestList: "  + this.props.interestList);
    }

    render() {
        return(
            <div className="Menu-container">
                este es el menu de la aplicacion
            </div>
        )
    }
}

export default Menu;

The console log from componentDidMount inside Menu component prints:

interestList: 
interestList: 

Any ideas to point me in the right direction? Greatly appreciated!

Henrik Andersson
  • 45,354
  • 16
  • 98
  • 92
Dieguinho
  • 758
  • 2
  • 14
  • 31
  • Are you sure Menu component is not loaded at two places in your UI. Also can you make sure that the `Main` component isn't pointing to `Menu` – Shubham Khatri Apr 30 '18 at 05:17
  • also the console.log is correct. you can test this in the console `"foo: " + []` – azium Apr 30 '18 at 05:22
  • possible Duplicate of https://stackoverflow.com/questions/43779411/reactjs-setting-state-from-props-using-setstate-in-componentwillreceiveprops-f/43780546#43780546 – Shubham Khatri Apr 30 '18 at 05:24
  • @ShubhamKhatri yes, I'm positive, the component that is really rendering twice is the **Members** component, the **Main** and the **Menu** components are plain Html, I've made another post with the code for the double rendering problem, please take a look at it here: [link](https://stackoverflow.com/questions/50089744/react-app-componentdidmount-rendering-twice?noredirect=1#comment87195965_50089744). Just saw your reference to duplicate, my case is I'm using `componentDidMount` so it should be called after the component rendered and should have the props passed by the parent – Dieguinho Apr 30 '18 at 05:46
  • @azium that is right, the thing is that the first call is empty, but the second call returns an array with information, not an empty array, so it should show in the console – Dieguinho Apr 30 '18 at 05:47
  • 3
    no it shouldn't show in the console precisely because `componentDidMount` only runs once, when the component mounts. when `Members` component calls `setState` and pass new props to `Menu`, it has already mounted so that function and your console log won't be called again with the populated array. you can test this easily by moving your console log into the `render` function – azium Apr 30 '18 at 06:18
  • @azium ok, I dont get it, putting the console.log inside the render function renders it 3 times, meaning that theres a third time being called from another lifecycle besides de create lifecycle. You are right, the third time prints the props, but shouldnt the component receive the props before its being created? I mean, I've read that the constructor is called before the component does the render, and receives the props from the parent this way... – Dieguinho Apr 30 '18 at 14:54
  • 2
    The component **is** receiving the props before being created, but the prop is an empty array. You explicitly say that in your `Members` constructor. Then after `Members` mounts you call `setState` which triggers **another** render with the populated array. [Read the docs](https://reactjs.org/docs/state-and-lifecycle.html) for a full explanation/ – azium Apr 30 '18 at 14:59

2 Answers2

1

For the answer look at @azium's comments:

no it shouldn't show in the console precisely because componentDidMount only runs once, when the component mounts. when Members component calls setState and pass new props to Menu, it has already mounted so that function and your console log won't be called again with the populated array. you can test this easily by moving your console log into the render function
The component is receiving the props before being created, but the prop is an empty array. You explicitly say that in your Members constructor. Then after Members mounts you call setState which triggers another render with the populated array. Read the docs for a full explanation/

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Dieguinho
  • 758
  • 2
  • 14
  • 31
0

If you're planning on manipulating that prop in your component, create a state in your compenent and assign it that prop. You still won't be able to do it in componentDidMount but you can use componentDidUpdate and setState in there. word of caution, make sure you always run a compare to prevProps or you'll end up with an infinite loop type error.

class Menu extends Component {
    constructor(props){
        super(props);
        this.state = {
          interestList: []
        };
    }

      componentDidUpdate(prevProps) {
        // compare props
        if (this.props.interestList !== prevProps.interestList) {
          this.setState({
            interestList: this.props.interestList
          })
        }
      }
    componentDidMount(){
        // won't work
        console.log("interestList: "  + this.props.interestList);
    }

    render() {
        return(
            <div className="Menu-container">
                este es el menu de la aplicacion
            </div>
        )
    }
}

export default Menu;
sigmapi13
  • 2,355
  • 3
  • 30
  • 27