2016-01-18 28 views
7

Wiem, że jest kilka podobnych pytań here i here, ale mam trudny czas zrozumieć, co jest prawidłowe myślenie dzisiaj na ten temat i ekstrapolować go do mojej sytuacji.react.js zadzwoń do funkcji rodzicielskiej od dziecka

Mam prostą aplikację, ScoreBox ma ScoreList, który ma wiele wyników. Chcę mieć Score onClick call ScoreList handleScoreRemove. Jestem pokazując pełny plik js, ale najważniejsze są linie linii 5 i linii 77.

var Score = React.createClass({ 
    removeRecord: function(e){ 
     // How do I do this? 
     ScoreList.handleScoreRemove(e); 
    }, 
    render: function() { 
    var team1_style = (this.props.team1_score >= this.props.team2_score) ? 
     {fontWeight: 'bold'} : {}; 
    var team2_style = (this.props.team2_score >= this.props.team1_score) ? 
      {fontWeight: 'bold'} : {}; 
     return (
      <tr> 
       <td style={team1_style}>{this.props.team1_name}:</td><td style={team1_style}>{this.props.team1_score}</td> 
       <td style={team2_style}>{this.props.team2_name}:</td><td style={team2_style}>{this.props.team2_score}</td> 
       <td><a hef="#" id={this.props.id} onClick={this.removeRecord}>remove</a></td> 
      </tr> 
    ); 
    } 
}); 

var ScoreBox = React.createClass({ 
    loadScoresFromServer: function() { 
    $.ajax({ 
     url: this.props.url, 
     dataType: 'json', 
     cache: false, 
     success: function(data) { 
     this.setState({data: data}); 
     }.bind(this), 
     error: function(xhr, status, err) { 
     console.error(this.props.url, status, err.toString()); 
     }.bind(this) 
    }); 
    }, 
    handleScoreSubmit: function(score) { 
    var scores = this.state.data; 
    // Optimistically set an id on the new score. It will be replaced by an 
    // id generated by the server. In a production application you would likely 
    // not use Date.now() for this and would have a more robust system in place. 
    score.id = Date.now(); 
    var newScores = scores.concat([score]); 
    this.setState({data: newScores}); 
    $.ajax({ 
     url: this.props.url, 
     dataType: 'json', 
     type: 'POST', 
     data: score, 
     success: function(data) { 
     this.setState({data: data}); 
     }.bind(this), 
     error: function(xhr, status, err) { 
     this.setState({data: scores}); 
     console.error(this.props.url, status, err.toString()); 
     }.bind(this) 
    }); 
    }, 
    getInitialState: function() { 
    return {data: []}; 
    }, 
    componentDidMount: function() { 
    this.loadScoresFromServer(); 
    setInterval(this.loadScoresFromServer, this.props.pollInterval); 
    }, 
    render: function() { 
    return (
     <div className="scoreBox"> 
     <h1>Scores</h1> 
     <ScoreList data={this.state.data} /> 
     <ScoreForm onScoreSubmit={this.handleScoreSubmit} /> 
     </div> 
    ); 
    } 
}); 

var ScoreList = React.createClass({ 
    handleScoreRemove: function(score) { 
    var scores = this.state.data; 
    var index_of_score = array.indexOf(score); 
    var newScores = scores.splice(index_of_score, 1); 
    this.setState({data: newScores}); 
    $.ajax({ 
     url: this.props.url + "/" + score[id], 
     dataType: 'json', 
     type: 'DELETE', 
     success: function(data) { 
     this.setState({data: data}); 
     }.bind(this), 
     error: function(xhr, status, err) { 
     this.setState({data: scores}); 
     console.error(this.props.url, status, err.toString()); 
     }.bind(this) 
    }); 
    }, 
    render: function() { 
    var scoreNodes = this.props.data.map(function(score) { 
     return (
     <Score key={score.id} id={score.id} team1_name={score.team1_name} team1_score={score.team1_score} team2_name={score.team2_name} team2_score={score.team2_score} > 
     </Score> 
    ); 
    }); 
    return (
     <div className="scoreList"> 
     <table> 
      <tbody> 
      {scoreNodes} 
      </tbody> 
     </table> 
     </div> 
    ); 
    } 
}); 

var ScoreForm = React.createClass({ 
    checkForCompleteForm: function(){ 
    if (this.state.team1_name.length > 0 && this.state.team2_name.length > 0 && this.state.team1_score.length > 0 && this.state.team2_score.length > 0) 
    { 
     // enable the button 
     $("input[type=submit]").removeAttr('disabled'); 
    } 

    }, 
    getInitialState: function() { 
    return {id: '', team1_name: '', team1_score: '', team2_name: '', team2_score: ''}; 
    }, 
handleChange : function (e) { 
    // this is a generic handle change function that uses the html id to set the state instead of 
    // having a bunch of if statements 
    var stateObject = function() { 
     var returnObj = {}; 
     returnObj[this.target.id] = this.target.value; 
     return returnObj; 
    }.bind(e)(); 
    // setState is async which makes this painful 
    // JCN - why when I pass checkForCompleteForm as 2nd param it doesnt work, but instead I need this 
    // function bind stuff... need to understand exactly what this is doing 
    this.setState(stateObject, function(){ 
     this.checkForCompleteForm(); 
    }.bind(this)); 
    }, 
    handleSubmit: function(e) { 
    e.preventDefault(); 
    var team1_name = this.state.team1_name.trim(); 
    var team1_score = this.state.team1_score.trim(); 
    var team2_name = this.state.team2_name.trim(); 
    var team2_score = this.state.team2_score.trim(); 
    if (!team1_name || !team1_score) { 
     return; 
    } 
    this.props.onScoreSubmit({team1_name: team1_name, team1_score: team1_score,team2_name: team2_name, team2_score: team2_score }); 
    this.setState({team1_name: '', team1_score: '', team2_name: '', team2_score: ''}); 
    }, 
    render: function() { 
    return (
     <form className="scoreForm" onSubmit={this.handleSubmit}> 
     <input 
      id='team1_name' 
      type="text" 
      placeholder="Team1 Name" 
      value={this.state.team1_name} 
      onChange={this.handleChange} 
     /> 
     <input 
      id='team1_score' 
      type="number" 
      placeholder="Team1 Score" 
      value={this.state.team1_score} 
      onChange={this.handleChange} 
     /> 
     <input 
      id='team2_name' 
      type="text" 
      placeholder="Team2 Name" 
      value={this.state.team2_name} 
      onChange={this.handleChange} 
     /> 
     <input 
      id='team2_score' 
      type="number" 
      placeholder="Team2 Score" 
      value={this.state.team2_score} 
      onChange={this.handleChange} 
     /> 
     <input type="submit" value="Post" disabled /> 
     </form> 
    ); 
    } 
}); 

ReactDOM.render(
    <ScoreBox url="/api/scores" pollInterval={2000} />, 
    document.getElementById('content') 
); 
+0

Wszystkie 3 odpowiedzi były dobre, wybrałem ten, który był najłatwiejszy do naśladowania. Dzięki wszystkim, co pomogło. – Joelio

Odpowiedz

9

Trzeba zdać handleScoreRemove przez props

var scoreNodes = this.props.data.map(function(score) { 
    return <Score 
    key={score.id} 
    id={score.id} 
    team1_name={score.team1_name} 
    team1_score={score.team1_score} 
    team2_name={score.team2_name} 
    team2_score={score.team2_score} 
    handleScoreRemove={this.handleScoreRemove.bind(this)}> 
    </Score> 
}, this); 

aw Score składnika nazwać jak ten

removeRecord: function(e) { 
    this.props.handleScoreRemove(/* add arguments what do you need */); 
}, 
2

Należy zdać handleScoreRemove jako rekwizyt do Score:

W ScoreList:

var scoreNodes = this.props.data.map(function(score) { 
    return (
    <Score key={score.id} (...) handleScoreRemove={this.handleScoreRemove}> 
    </Score> 
); 
}); 

W Score:

removeRecord: function(e){ 
    this.props.handleScoreRemove(this); 
} 
3

wywołanie funkcji nadrzędnej z dzieckiem

You don” t (jak co o term posty mówią). Ty przekazaćhandleScoreRemove do dziecka jako rekwizyt. Wewnątrz dziecka wywołujesz funkcję, wywołując rekwizyt. W dalszej części handleScoreRemove jest przekazywane jako podpora onScoreRemove wewnątrz dziecka.

<Score ...stuff... onScoreRemove={this.handleScoreRemove}></Score> 

Jesteś już robi to samo z ScoreBox (rodzica) i ScoreForm (dziecko). W teście podałeś referencję handleScoreSubmit jako propa onScoreSubmit.

<ScoreForm onScoreSubmit={this.handleScoreSubmit} /> 
Powiązane problemy