React似乎没有将道具传递给另一个组件

时间:2016-11-18 08:15:21

标签: javascript reactjs

我遵循了如何构建React应用程序的教程,并且我遇到了一些奇怪的问题。

当我尝试将一些信息传递给另一个组件时,另一个组件获得props但它是空的。

就我而言,index.js就是这样:

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' )
);

./components/video_list.js中的代码是这样的:

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;

代码似乎非常具有战略性,但实际上它存在问题。

如果我在console.log( this.state.videos );的{​​{1}}语句之前尝试此语句return,我会得到以下输出:

index.js

同时,如果我在// 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] 组件的console.log( props )方法中尝试constructor,我会得到以下输出:

VideoList

你知道什么是错的吗?你看到我看不到的东西吗?

2 个答案:

答案 0 :(得分:1)

关于这个 -

同时如果我在VideoList组件的构造函数方法中尝试console.log(props),我会得到以下输出:

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

这是绝对正确的行为。

这种情况正在发生,因为在反应组件生命周期中,您的子组件首先被渲染,此时您传递给子组件的道具将具有默认值或空值(例如[])。

现在你的孩子被渲染了父渲染。

当父完全呈现componentDidMount父方法被调用时,你已经发出了一些ajax请求来下载动态数据,在你的情况下是视频列表。

你正在做这件事,这也是完全有效的 -

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

数据通过ajax进入之后,您在父组件中再次设置状态,这会导致渲染周期再次发生。

            this.setState ( { videos } );

现在您的孩子将收到更新的新视频列表数组。

再次发生孩子的渲染,这将有视频列表。

但是,由于您更改了父道具并接收新道具,因此您需要添加新的生命周期方法。

componentWillReceiveProps

您可以在此处将old propsnew props进行比较,并将状态设置为更新的道具。这将使子组件呈现最新的更新数据。

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

答案 1 :(得分:0)

在“./components/video_list.js”

不使用 componentDidMount 设置状态,而是使用 componentWillReceiveProps()

OR  在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' )
);