'this' 尽管在构造函数中进行了适当的绑定,但对象仍未定义 (React)

'this' object undefined despite proper binding in constructor function (React)

我刚刚开始使用 React,正在构建一个应用程序,该应用程序通过 Youtube 的 API 进行视频搜索。在查询 API 视频后,我正在尝试在我的 "search-results" div 中动态呈现视频数据。

这个 "search-results" div 应该渲染一个名为 searchResults 的 JSX 数组,它存储为 AddSong 组件的状态键值对。在构建组件时,这个数组是空的,它应该被填充到 axios get 请求的 .then(function(response){} 函数中(在我的搜索函数中)。

在此函数中,我逐项从 API 响应中提取相关数据。对于每个项目,我将数据格式化为 JSX,并将其存储到名为 vidComponents 的本地数组中。当我调用 this.setState({searchResults: vidComponents}) 时出现问题。 'This' 未定义。具体错误如下:

TypeError: 无法读取未定义的 属性 'setState'

经过一些研究后,我了解到大多数人之所以会出现此错误,是因为没有在构造函数中正确地将 'this' 绑定到相关函数,但我并非如此。 'This' 在构造函数中绑定到我的搜索函数,如下所示:

this.search = this.search.bind(这个)

有谁知道是什么导致了这个错误?这是我的代码:

import React, { Component } from 'react';
import axios from 'axios';
import { FormGroup, FormControl, Button } from 'react-bootstrap';
import './add-song-component.css';

class AddSong extends React.Component{
    constructor(props, context){
        super(props, context);

        // Must bind this to functions in order for it to be accessible within them
        this.handleTextChange = this.handleTextChange.bind(this);
        this.search = this.search.bind(this);

        // Object containing state variables
        this.state = {
            searchText: '',
            searchResults: [],
            nextPageToken: ''
        };
    }

    // Keeps track of the current string in the search bar
    handleTextChange(e){
        this.setState({ searchText: e.target.value });
    }

    // Runs a search for 10 youtube videos through youtube's API
    search(e){
        // Initialize important data for formatting get request url
        var api = this.props.apiKey;
        var query = this.state.searchText;
        var maxResults = 10;

        // Execute get request on Youtube's search API
        axios.get('https://www.googleapis.com/youtube/v3/search', {
            params: {
                part: 'snippet',
                type: 'video',
                order: 'viewCount',
                key: api,
                q: query,
                maxResults: maxResults
            }
        })
        .then(function (response) {
            console.log(response.data);

            var vidComponents = [];

            // Loop through video data, extract relevant info
            var i = 0;
            for (let vidInfo of response.data.items) {
                vidComponents.push(
                    <div key={i}>
                        <p>title: {vidInfo.snippet.title}</p>
                        <p>channel: {vidInfo.snippet.channelTitle}</p>
                        <p>id: {vidInfo.id.videoId}</p>
                        <p>thumbnailUrl: {vidInfo.snippet.thumbnails.high.url}</p>
                    </div>
                );
                i++;
            }

            // Set searchResults state to account for new results...
            // Set nextPageToken state based on value from youtube's response
            // *** used for retrieving more videos from initial query ***
            this.setState({
                searchResults: vidComponents,
                nextPageToken: response.data.nextPageToken
            });
        })
        .catch(function (error) {
            console.log(error);
        }); 
    }

    render(){
        return(
            <div className="add-song">
                <form>
                    <FormGroup controlId="SearchText">
                        <FormControl 
                            type="text"
                            placeholder="Search for a song / video"
                            value={this.state.searchText}
                            onChange={this.handleTextChange}
                        />
                    </FormGroup>
                    <Button onClick={this.search}>Search</Button>
                </form>

                <div className="search-results">
                    {this.state.searchResults}
                </div>
            </div>
        );
    }
}

export default AddSong; 
handleTextChange = e => {
    this.setState({ searchText: e.target.value });
}

此语法会将 this 绑定到当前的 class。在您的情况下, this 将指向当前函数范围,因此您将获得 undefined

您缺少 this 绑定到您的 handleTextChange function.So,它不是用组件 this 对象调用的。

解决方案1:在构造函数内部使用绑定

constructor(props, context){
        super(props, context);
       //...
       this. handleTextChange = this.handleTextChange.bind(this);
}

解决方案 2:使用 arrow function.

handleTextChange =(e)=>{
        this.setState({ searchText: e.target.value });
    }

恕我直言,您的 searchhandleSearch 函数在构造函数中的作用域都很好。那应该不是问题。但我确实在你的 search 函数中看到一个 setState

axios.get(...).then(function() { this.setState(...) }

如果能改用箭头函数就更好了!

axios.get(...).then(() => { this.setState(...) }