KodeFor.Me
KodeFor.Me

Reputation: 13521

React seems like doesn't pass props to another component

I follow a tutorial on how to build a React application, and I am stacked with a kind of strange issue.

When I try to pass some information to another component, the other component getting the props but it is empty.

In my case, the index.js is like that:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import YTSearch from 'youtube-api-search';

import SearchBar from './components/search_bar';
import VideoList from './components/video_list';

const API_KEY = 'AIzaSyDdvc_zComCpdqqfmwgOsZvLOwwPEabcde';

class App extends Component {
    constructor ( props ) {
        super ( props );

        this.state = {
            videos : []
        };
    }

    componentDidMount() {
        YTSearch (
            {
                key  : API_KEY,
                term : 'surfboards'
            },
            videos => {
                this.setState ( { videos } );
            }
        );
    }

    render () {
        return (
            <div>
                <SearchBar />
                <VideoList videos={this.state.videos} />
            </div>
        );
    }
};

ReactDOM.render (
    <App />,
    document.querySelector ( '.container' )
);

and my code in the ./components/video_list.js is like this:

import React, { Component } from 'react';

import VideoListItem from './video_list_item';

class VideoList extends Component {
    constructor( props ) {
        super( props );

        this.state = {
            videoItems : []
        };
    }

    componentDidMount() {
        this.setState(
            {
                videoItems: this.props.videos.map(
                    video => {
                        console.log( video );
                        return <VideoListItem video={video} />;
                    }
                )
            }
        )
    }

    render() {
        return (
            <ul className="col-md-4 list-group">{ this.state.videoItems }</ul>
        );
    }
}

export default VideoList;

The code seems to be very strateforward, but in reality it has issues.

If I try this statement console.log( this.state.videos ); before the return statement in the index.js I get the following output:

// Initially I get this because the API is not yet completed:
Array[0]
    length: 0
    __proto__: Array[0]

// And then, once the API Request it is completed I get this:
Array[5]
    0: Object
        etag : ""5C5HHOaBSHC5ZXfkrT4ZlRCi01A/2H00YaVLWV4Xof09xk9Q8k6vlxw""
        id: Object
        kind: "youtube#searchResult"
        snippet: Object
        __proto__: Object
    1: Object
    2: Object
    3: Object
    4: Object
    length: 5
    __proto__: Array[0]

At the same time if I try a console.log( props ) inside the constructor method of the VideoList component I get the following output:

Object {videos: Array[0]}
    videos: Array[0]
        length: 0
        __proto__: Array[0]
    __proto__: Object

Do you have any idea of what can be wrong ? Do you see something I don't see ?

Upvotes: 0

Views: 117

Answers (2)

Gaurav joshi
Gaurav joshi

Reputation: 1799

In "./components/video_list.js"

Instead of setting state on componentDidMount use componentWillReceiveProps()

OR in index.js

const API_KEY = 'AIzaSyDdvc_zComCpdqqfmwgOsZvLOwwPEabcde';

class App extends Component {
    constructor ( props ) {
        super ( props );

        this.state = {
            videos : []
        };
    }

    componentDidMount() {
        YTSearch (
            {
                key  : API_KEY,
                term : 'surfboards'
            },
            videos => {
                this.setState ( { videos } );
            }
        );
    }

    render () {
        const { videos } = this.state
        return (
            <div>
                <SearchBar />

                {videos.length ?
                    <VideoList videos={this.state.videos} />
                : null
                }
            </div>
        );
    }
};

ReactDOM.render (
    <App />,
    document.querySelector ( '.container' )
);

Upvotes: 0

WitVault
WitVault

Reputation: 24140

Regarding this -

At the same time if I try a console.log( props ) inside the constructor method of the VideoList component I get the following output:

Object {videos: Array[0]}
    videos: Array[0]
        length: 0
        __proto__: Array[0]
    __proto__: Object

This is absolutely correct behaviour.

This is happening because during react component life cycle your child component gets rendered first and at that time props which you are passing to your child component will be having default or empty values ( e.g []).

Now your child gets rendered the parent rendering happens.

When parent gets rendered completely componentDidMount method of parent gets called in which you have made some ajax request to download dynamic data which in your case is video lists.

Which you are doing like this and this is also perfectly valid -

componentDidMount() {
    YTSearch (
        {
            key  : API_KEY,
            term : 'surfboards'
        },
        videos => {
            this.setState ( { videos } );
        }
    );
}

After the data comes in via ajax you set the state again in your parent component which causes rendering cycle to happen again.

            this.setState ( { videos } );

Now your child will receive updated new video list array.

And rendering of child happens again which will be having video lists.

But since you have parent props changed and to receive new props you need to add a new life cycle method.

componentWillReceiveProps

Here you can compare old props with new props and set the states to the updated props. Which will render the child component with latest updated data.

componentWillReceiveProps(nextProps) {
        this.setState(
            {
                videoItems: nextProps.videos.map(
                    video => {
                        console.log( video );
                        return <VideoListItem video={video} />;
                    }
                )
            }
        )
}

Upvotes: 1

Related Questions