'этот' объект не определен, несмотря на правильную привязку в функции конструктора (React)

Я только начинаю работать с React и создаю приложение, которое включает поиск видео через API Youtube. Я пытаюсь динамически отображать видеоданные в моем div «результаты поиска» после запроса видео к API.

Этот div "search-results" должен отображать массив JSX под названием searchResults, который хранится как пара ключ-значение состояния компонента AddSong. После создания компонента этот массив пуст, и он должен быть заполнен функцией .then (function (response) {} запроса на получение axios (в моей функции поиска).

В этой функции я извлекаю соответствующие данные из ответа API элемент за элементом. Для каждого элемента я форматирую данные в JSX и сохраняю их в локальном массиве под названием vidComponents. Моя проблема возникает, когда я вызываю this.setState ({searchResults: vidComponents}). «Это» не определено. Точная ошибка указана ниже:

TypeError: невозможно прочитать свойство setState из undefined

Проведя небольшое исследование, я узнал, что большинство людей получают эту ошибку из-за неправильной привязки 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; 

person Chris Ragsdale    schedule 16.03.2018    source источник
comment
Вы отлаживали свой код?   -  person Jeroen Heier    schedule 16.03.2018
comment
проблема находится внутри метода axios. затем вам нужно привязать его для доступа к this внутри, например: .then((response) => {....}   -  person Mayank Shukla    schedule 16.03.2018
comment
this в событии относится к объекту, которому принадлежит событие. Другими словами, элемент.   -  person StackSlave    schedule 16.03.2018
comment
Возможный дубликат как выполнить обратный вызов setState   -  person Mayank Shukla    schedule 16.03.2018
comment
Вы были правы, Маянк. Спасибо!   -  person Chris Ragsdale    schedule 16.03.2018
comment
Нашел статью, в которой объясняется обходной путь на тот случай, если другие новички наткнутся на это: hackernoon.com/ ...   -  person Chris Ragsdale    schedule 16.03.2018


Ответы (3)


IMHO обе ваши search и handleSearch функции хорошо определены в конструкторе. Это не должно быть проблемой. Но я действительно вижу setState внутри вашей search функции:

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

Было бы лучше, если бы вы могли использовать вместо этого функцию стрелки!

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

person semuzaboi    schedule 16.03.2018

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

Этот синтаксис привяжет this к текущему классу. Хотя в вашем случае this будет указывать на текущую область действия, поэтому вы получаете undefined

person Sagar Jajoriya    schedule 16.03.2018
comment
нет проблем с этим кодом, проблема в этой строке: .then(function (response) {, OP забыл привязать метод axios .then. это должно быть .then((response) => { - person Mayank Shukla; 16.03.2018

вам не хватает this привязки к вашей handleTextChange функции, поэтому она не вызывается с объектом this Component.

решение1: использование привязки внутри конструктора

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

Решение 2. Использование arrow function < / сильный>.

handleTextChange =(e)=>{
        this.setState({ searchText: e.target.value });
    }
person RIYAJ KHAN    schedule 16.03.2018
comment
Нет, не поэтому. Посмотрите, где находится this.setState - person Andrew; 16.03.2018
comment
@Andrew, да, его область видимости AddSong Component this. Но при вызове. handleTextChange его нельзя привязать к компоненту this - person RIYAJ KHAN; 16.03.2018
comment
@RIYAJKHAN, с этим кодом проблем нет, проблема в этой строке: .then(function (response) {, OP забыл привязать метод axios .then. это должно быть .then((response) => {..} - person Mayank Shukla; 16.03.2018