2017-05-09 3 views
0

Ich benutze react-bootstrap-typeahead asynchronous searching. In der renderMenuItemChildren Methode möchte ich eine andere Methode handleSubmit aufrufen, um Details des ausgewählten Elements abzurufen.'this' undefined in renderMenuItemChildren

this ist innerhalb renderMenuItemChildren undefined und ich kann die Methode nicht aufrufen. Jede Hilfe wird geschätzt.

P.S. Ich lerne immer noch reagieren, also könnte es einen dummen Fehler geben, den ich nicht identifizieren kann.

class App extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     searchTitle: '', 
     defaultUrl: 'http://www.omdbapi.com/?t=arrival' 
    }; 
    this.handleSearch = this.handleSearch.bind(this); 
    this.handleSubmit = this.handleSubmit.bind(this); 
    this.fetchApiData = this.fetchApiData.bind(this); 
    } 

    componentDidMount() { 
    this.fetchApiData(this.state.defaultUrl); 
    } 

    fetchApiData(url){ 
    fetch(url) 
    .then((result) => { 
     return result.json() 
    }) 
    .then((json) => { 
     if(json.Response === "True"){ 
      this.setState({ 
      title: json.Title, 
      year: json.Year, 
      released: json.Released, 
      runtime: json.Runtime, 
      genreList: json.Genre, 
      actors: json.Actors, 
      plot: json.Plot, 
      poster_url: json.Poster, 
      rating: json.imdbRating, 
      boxOffice: json.BoxOffice, 
      votes: json.imdbVotes, 
      response: json.Response 
     }); 
     } 
     else { 
     this.setState({ 
      response: json.Response, 
      error: json.Error 
     }); 
     } 
    }) 
    .catch((err) => { 
     console.log(err); 
    }) 
    } 

    handleSubmit(query){ 
    if (!query) { 
     return; 
    } 
    this.fetchApiData(`http://www.omdbapi.com/?t=${query}`); 
    } 

    handleSearch(query) { 
    if (!query) { 
     return; 
    } 

    fetch(`http://www.omdbapi.com/?s=${query}`) 
     .then((result) => { 
     return result.json() 
     }) 
     .then((json) => { 
     //console.log(json.Search); 
     this.setState({ 
      options: json.Search 
     }) 
     }); 
    } 

    renderMenuItemChildren(option, props, index) { 
    return (
     <div key={option.imdbID} onClick={() => 
     this.handleSubmit.bind(option.Title)}> 
     <span>{option.Title}</span> 
     </div> 
    ); 
    } 

    render() { 
    return (
     <div className="row"> 
     <div className="col-xs-12 col-lg-10 col-lg-offset-1"> 
      <div className="App-header col-xs-12"> 
      <div className="row"> 
       <div className="col-xs-12 col-sm-6 col-lg-5"> 
       <h1><a href="http://www.omdbapi.com/" className="omdb-link" title="The Open Movie Database">OMDb</a></h1> 
       </div> 
       <div className="col-xs-12 col-sm-6 col-lg-7"> 

       <AsyncTypeahead 
        ref="typeahead" 
        {...this.state} 
        labelKey="Title" 
        onSearch={this.handleSearch} 
        options={this.state.options} 
        placeholder='Search Title' 
        className="search-input-box" 
        renderMenuItemChildren={this.renderMenuItemChildren} 
       /> 
       </div> 
      </div> 
      </div> 
      <SearchBody data={this.state} /> 
     </div> 
    </div> 
    ); 
    } 
    } 

Antwort

0

Sie brauchen nicht => Funktion hier. Sie können unter Code verwenden, um den Titel Wert zu übergeben zurück zu handleSubmit()

renderMenuItemChildren(option, props, index) { 
    return (
    <div key={option.imdbID} onClick={this.handleSubmit.bind(this, option.Title)}> 
     <span>{option.Title}</span> 
    </div> 
); 
} 
+0

danke für die Lösung. Obwohl dies nicht ganz funktionierte, musste ich renderMenuItemChildren wie von @ T.J vorgeschlagen binden. Crowder too –

+0

Idealerweise brauchen Sie es nicht an der Stelle, d. H. Beim Aufruf und im Konstruktor, zu binden. Jeder von diesen sollte ausreichen. Aber wie auch immer, ich bin froh, dass dir die Lösung etwas geholfen hat. – ivp

2

Sie müssen auch die Funktion renderMenuItemChildren im Konstruktor binden:

hinzufügen:

this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this); 

Hier ist eine nette kleine Blog-Post mit mehreren Möglichkeiten, um dies: Blog Post That sagte ich bevorzuge lodashs bindAll:

_.bindAll(this, function1, function2, function3)

+1

Danke für den Link Beitrag zum Blog :) –

1

Sie müssen tun, was Sie für Ihre anderen Methoden gemacht haben (handleSearch, handleSubmit, etc.) im Konstruktor:

this.renderMenuItemChildren = this.renderMenuItemChildren.bind(this); 

(Oder mehrere andere Möglichkeiten, aber das ist die Art und Weise Sie verwenden für Ihre anderen Methoden, so ...)

+0

danke, ist renderMenuItemChildren ein Verfahren zur Herstellung AsyncTypeahead so dachte ich, ich könnte es nicht binden müssen. –

1

Während renderMenuItemChildren.bind(this) in Konstruktor wird auf jeden Fall funktioniert, es6 Klassen können Ihnen auch Pfeil Funktion Ausdrücke als Klassenmethoden verwenden. Dies bindet automatisch this (oder, mit anderen Worten, Kontext) an die Methode, reduziert die Menge des Standardcodes und erleichtert das Lesen Ihrer Komponenten.

So Ihr Code so etwas wie dies sein könnte:

class App extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     searchTitle: '', 
     defaultUrl: 'http://www.omdbapi.com/?t=arrival' 
    }; 
    } 

    // etc... 

    renderMenuItemChildren =() => { 
    // do stuff 
    } 
}