2017-08-05 2 views
0

Ich versuche zu verwenden, reagieren, um eine Liste von Elementen zu erstellen und den Zustand des übergeordneten Elements dieser Liste zu aktualisieren, wenn ein einzelnes Element angeklickt wird.Update React Grandparent State von onClick in Grandchild

Der gesamte Behälter ist App.jsx (die Großeltern)

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

    this.state = { 
     selectedClass: null, 
     query: "cs 2110" 
    } 

    this.handleSelectClass.bind(this); 
    } 

    handleSelectClass(classId) { 
    console.log(classId); 

    //get the id of the course and get full course details 
    Meteor.call('getCourseById', classId, function(error, result) { 
     if (!error) { 
     console.log(this.state); 
     this.setState({selectedClass: result, query: ""}, function() { 
      console.log(this.state.selectedClass); 
      console.log(this.state.query); 
     }); 
     } else { 
     console.log(error) 
     } 
    }); 
    } 

    //check if a class is selected, and show a coursecard only when one is. 
    renderCourseCard() { 
    var toShow = <div />; //empty div 
    if (this.state.selectedClass != null) { 
     toShow = <CourseCard course={this.state.selectedClass}/>; 
    } 
    return toShow; 
    } 

    render() { 
    return (
     <div className="container"> 
     <header> 
      <h1>Todo List</h1> 
     </header> 
     <div className='row'> 
      <input /> 
      <Results query={this.state.query} clickFunc={this.handleSelectClass}/> 
     </div> 
     <div className='row'> 
      <div className="col-md-6"> 
      {this.renderCourseCard()} 
      </div> 
      <div className="col-md-6 panel-container fix-contain"> 
      <Form courseId="jglf" /> 
      </div> 
     </div> 
     </div> 
    ); 
    } 
} 

den übergeordneten Container ist Results.jsx

export class Results extends Component { 
    constructor(props) { 
    super(props); 
    } 

    renderCourses() { 
    if (this.props.query != "") { 
     return this.props.allCourses.map((course) => (
     //create a new class "button" that will set the selected class to this class when it is clicked. 
     <Course key={course._id} info={course} handler={this.props.clickFunc}/> 
    )); 
    } else { 
     return <div />; 
    } 
    } 

    render() { 
    return (
     <ul> 
     {this.renderCourses()} 
     </ul> 
    ); 
    } 
} 

und der Kurs Listenelement ist ein Enkelkind Komponente

export default class Course extends Component { 
    render() { 
    var classId = this.props.info._id; 
    return (
     <li id={classId} onClick={() => this.props.handler(classId)}>{this.props.info.classFull}</li> 
    ); 
    } 
} 

Ich folgte den Vorschlägen hier Reactjs - How to pass values from child component to grand-parent component?, um eine Callback-Funktion zu übergeben n, aber der Callback erkennt immer noch nicht den Zustand des Großelternteils. console.log (this.state) in App.jsx gibt undefined zurück, obwohl die classId korrekt ist, und der Fehler lautet: "Ausnahme bei der Ausgabe des Ergebnisses des Aufrufs von 'getCourseById': TypeError: this.setState ist keine Funktion"

Ist das ein Problem mit der Bindung? Ich habe dies ohne Kurs als eigene Komponente ausprobiert und habe das gleiche Problem.

Antwort

0

Schnell durch den Code suchen. Ich kann dieses Problem sehen, man liegt hier. Obwohl Sie Ihre Funktion an Ihre Komponente gebunden haben, verwenden Sie einen Meteor-Aufruf, der das Ergebnis in seinem eigenen Funktionsumfang definiert, was bedeutet, dass er nicht auf this.setState zugreifen kann. Sie können die Fettpfeil-Funktion verwenden, um dieses Problem zu umgehen, aber Sie müssen sicherstellen, dass Sie ES6 verwenden.

Meteor.call('getCourseById', classId, function(error, result) => { 
    if (!error) { 
    console.log(this.state); 
    this.setState({selectedClass: result, query: ""}, function() { 
     console.log(this.state.selectedClass); 
     console.log(this.state.query); 
    }); 
    } else { 
    console.log(error) 
    } 
}); 

TO

Meteor.call('getCourseById', classId, (error, result) => { 
    if (!error) { 
    console.log(this.state); 
    this.setState({selectedClass: result, query: ""},() => { 
     console.log(this.state.selectedClass); 
     console.log(this.state.query); 
    }); 
    } else { 
    console.log(error) 
    } 
}); 

Sie haben Ihre Funktion nicht richtig mit dem Bauteil auch binded.

this.handleClassSubmit = this.handleClassSubmit.bind(this); 
+0

Ich habe diese Änderungen versucht, aber ich bekomme immer noch undefined this.state in den Protokollen (obwohl es keinen Fehler gibt, druckt Meteor Debug "No Message"). Ich benutze den aktuellsten Meteor-Build, also glaube ich, dass es es6 läuft - ich sehe die Pakete es5-shim und [email protected] installiert. –

+0

Gerade gesehen, du bindest deine Funktion an die Komponente falsch, es ist 'this.handleSelectClass = this.handleSelectClass.bind (this);' – Win

+0

Ahh das habe ich vermisst - vielen Dank, das hat es behoben! –