react组件间通信(含实例)
下面用一个例子来说明https://github.com/zhengmiaohua/my-react-demos
第一种:父组件向子组件传递数据,一般用props,子组件想要改变父组件的数组,可以向子组件传递回调函数,层级多的话嵌套会很复杂
//stuScore1.html
const SCORE=[ {name: '张三', gender: '男', chinese: 85, math: 98, id:0}, {name: '张三', gender: '女', chinese: 95, math: 90, id:1}, {name: '李四', gender: '男', chinese: 65, math: 48, id:2}, {name: '大妹', gender: '女', chinese: 95, math: 100,id:3}, {name: '王五', gender: '男', chinese: 75, math: 88, id:4}, {name: '赵钱', gender: '男', chinese: 75, math: 98, id:5}, {name: '二妹', gender: '女', chinese: 90, math: 98, id:6} ]; class StudentScoreTable extends React.Component{ constructor(props){ super(props); this.state={ genderFilter:0, nameFilter:'' } this.onGenderChange=this.onGenderChange.bind(this); this.onNameChange=this.onNameChange.bind(this); } onGenderChange(gender){ this.setState({genderFilter:gender}); } onNameChange(name){ this.setState({nameFilter:name}) } render(){ return ( <div> <GenderInputBar onGenderChange={this.onGenderChange} genderFilter={this.genderFilter}/> <NameInputBar onNameChange={this.onNameChange} nameFilter={this.nameFilter}/> <ScoreTable scoreArr={this.props.score} genderFilter={this.state.genderFilter} nameFilter={this.state.nameFilter}/> </div> ); } } class ScoreTable extends React.Component{ constructor(props){ super(props); } render(){ let rows=[]; let genderFilter=this.props.genderFilter; let nameFilter=this.props.nameFilter; const GENDER=['','男','女'] this.props.scoreArr.map((scoreItem)=>{ if(genderFilter!==0&&nameFilter===''){ if(scoreItem.gender===GENDER[genderFilter]){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id}/>) } return; } if(genderFilter===0&&nameFilter!==''){ if(scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } if(genderFilter!==0&&nameFilter!==''){ if(scoreItem.gender===GENDER[genderFilter]&&scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) }) return ( <table className="gridtable"> <thead> <tr> <th>姓名</th> <th>性别</th> <th>语文</th> <th>数学</th> </tr> </thead> <tbody> {rows} </tbody> </table> ); } } class ScoreItem extends React.Component{ constructor(props){ super(props); } render(){ let score=this.props.score; return ( <tr> <td>{score.name}</td> <td>{score.gender}</td> <td>{score.chinese}</td> <td>{score.math}</td> </tr> ); } } class GenderInputBar extends React.Component{ constructor(props){ super(props); this.genderChangeHandler=this.genderChangeHandler.bind(this); } genderChangeHandler(e){ this.props.onGenderChange(e.target.value); } render(){ return ( <div> <from> <label>按性别筛选:</label> <select onChange={this.genderChangeHandler}> <option value="0">All</option> <option value="1">男</option> <option value="2">女</option> </select> </from> </div> ); } } class NameInputBar extends React.Component{ constructor(props){ super(props); this.nameChangeHandler=this.nameChangeHandler.bind(this) } nameChangeHandler(e){ this.props.onNameChange(e.target.value) } render(){ return ( <div> <form> <label htmlFor="nameInput">按姓名筛选:</label> <input type="text" id="nameInput" value={this.props.nameFilter} onChange={this.nameChangeHandler} /> </form> </div> ); } } ReactDOM.render( <StudentScoreTable score={SCORE} />, document.getElementById("root")); </script>
第二种:直接通过其组件句柄去直接访问其方法,没有了中间环节,代码也简洁了很多,把this指向赋给一个全局变量
//stuScore1.html
const SCORE=[ {name: '张三', gender: '男', chinese: 85, math: 98, id:0}, {name: '张三', gender: '女', chinese: 95, math: 90, id:1}, {name: '李四', gender: '男', chinese: 65, math: 48, id:2}, {name: '大妹', gender: '女', chinese: 95, math: 100,id:3}, {name: '王五', gender: '男', chinese: 75, math: 88, id:4}, {name: '赵钱', gender: '男', chinese: 75, math: 98, id:5}, {name: '二妹', gender: '女', chinese: 90, math: 98, id:6} ]; var _StudentScoreTable=null; class StudentScoreTable extends React.Component{ constructor(props){ super(props); this.state={ genderFilter:0, nameFilter:'' } //把StudentScoreTable组件赋值给一个变量,以便在其它组件中可以使用此组件的方法,直接通过其组件句柄去直接访问其方法 _StudentScoreTable=this; this.onGenderChange=this.onGenderChange.bind(this); this.onNameChange=this.onNameChange.bind(this); } onGenderChange(gender){ this.setState({genderFilter:gender}); } onNameChange(name){ this.setState({nameFilter:name}) } render(){ return ( <div> <GenderInputBar genderFilter={this.genderFilter}/> <NameInputBar nameFilter={this.nameFilter}/> <ScoreTable scoreArr={this.props.score} genderFilter={this.state.genderFilter} nameFilter={this.state.nameFilter}/> </div> ); } } class ScoreTable extends React.Component{ constructor(props){ super(props); } render(){ let rows=[]; let genderFilter=this.props.genderFilter; let nameFilter=this.props.nameFilter; const GENDER=['','男','女'] this.props.scoreArr.map((scoreItem)=>{ if(genderFilter!==0&&nameFilter===''){ if(scoreItem.gender===GENDER[genderFilter]){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id}/>) } return; } if(genderFilter===0&&nameFilter!==''){ if(scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } if(genderFilter!==0&&nameFilter!==''){ if(scoreItem.gender===GENDER[genderFilter]&&scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) }) return ( <table className="gridtable"> <thead> <tr> <th>姓名</th> <th>性别</th> <th>语文</th> <th>数学</th> </tr> </thead> <tbody> {rows} </tbody> </table> ); } } class ScoreItem extends React.Component{ constructor(props){ super(props); } render(){ let score=this.props.score; return ( <tr> <td>{score.name}</td> <td>{score.gender}</td> <td>{score.chinese}</td> <td>{score.math}</td> </tr> ); } } class GenderInputBar extends React.Component{ constructor(props){ super(props); this.genderChangeHandler=this.genderChangeHandler.bind(this); } genderChangeHandler(e){ _StudentScoreTable.onGenderChange(e.target.value); } render(){ return ( <div> <from> <label>按性别筛选:</label> <select onChange={this.genderChangeHandler}> <option value="0">All</option> <option value="1">男</option> <option value="2">女</option> </select> </from> </div> ); } } class NameInputBar extends React.Component{ constructor(props){ super(props); this.nameChangeHandler=this.nameChangeHandler.bind(this) } nameChangeHandler(e){ _StudentScoreTable.onNameChange(e.target.value) } render(){ return ( <div> <form> <label htmlFor="nameInput">按姓名筛选:</label> <input type="text" id="nameInput" value={this.props.nameFilter} onChange={this.nameChangeHandler} /> </form> </div> ); } } ReactDOM.render( <StudentScoreTable score={SCORE} />, document.getElementById("root")); </script>
第三种:发布订阅模式
//stuScore2.html
// eventProxy.js首先使用数组缓存订阅者订阅的消息,当订阅者订阅消息的时候,把订阅的消息push到指定消息的队列中,当发布者发布消息的时候,我们遍历执行push到指定消息队列中的回调事件。 'use strict'; const eventProxy = { onObj: {}, oneObj: {}, on: function(key, fn) { if(this.onObj[key] === undefined) { this.onObj[key] = []; } this.onObj[key].push(fn); }, one: function(key, fn) { if(this.oneObj[key] === undefined) { this.oneObj[key] = []; } this.oneObj[key].push(fn); }, off: function(key) { this.onObj[key] = []; this.oneObj[key] = []; }, trigger: function() { let key, args; if(arguments.length == 0) { return false; } key = arguments[0]; args = [].concat(Array.prototype.slice.call(arguments, 1)); if(this.onObj[key] !== undefined && this.onObj[key].length > 0) { for(let i in this.onObj[key]) { this.onObj[key][i].apply(null, args); } } if(this.oneObj[key] !== undefined && this.oneObj[key].length > 0) { for(let i in this.oneObj[key]) { this.oneObj[key][i].apply(null, args); this.oneObj[key][i] = undefined; } this.oneObj[key] = []; } } }; const GenderFilterChangeEvt = 'genderFilter change event'; const NameFilterChangeEvt = 'nameFilter change event'; const SCORE=[ {name: '张三', gender: '男', chinese: 85, math: 98, id:0}, {name: '张三', gender: '女', chinese: 95, math: 90, id:1}, {name: '李四', gender: '男', chinese: 65, math: 48, id:2}, {name: '大妹', gender: '女', chinese: 95, math: 100,id:3}, {name: '王五', gender: '男', chinese: 75, math: 88, id:4}, {name: '赵钱', gender: '男', chinese: 75, math: 98, id:5}, {name: '二妹', gender: '女', chinese: 90, math: 98, id:6} ]; class StudentScoreTable extends React.Component{ constructor(props){ super(props); this.state={ genderFilter:0, nameFilter:'' } this.onGenderChange=this.onGenderChange.bind(this); this.onNameChange=this.onNameChange.bind(this); } onGenderChange(gender){ this.setState({genderFilter:gender}); } onNameChange(name){ this.setState({nameFilter:name}) } componentDidMount(){ eventProxy.on(GenderFilterChangeEvt,this.onGenderChange); eventProxy.on(NameFilterChangeEvt,this.onNameChange); } render(){ return ( <div> <GenderInputBar genderFilter={this.genderFilter}/> <NameInputBar nameFilter={this.nameFilter}/> <ScoreTable scoreArr={this.props.score} genderFilter={this.state.genderFilter} nameFilter={this.state.nameFilter}/> </div> ); } } class ScoreTable extends React.Component{ constructor(props){ super(props); } render(){ let rows=[]; let genderFilter=this.props.genderFilter; let nameFilter=this.props.nameFilter; const GENDER=['','男','女'] this.props.scoreArr.map((scoreItem)=>{ if(genderFilter!==0&&nameFilter===''){ if(scoreItem.gender===GENDER[genderFilter]){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id}/>) } return; } if(genderFilter===0&&nameFilter!==''){ if(scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } if(genderFilter!==0&&nameFilter!==''){ if(scoreItem.gender===GENDER[genderFilter]&&scoreItem.name===nameFilter){ rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) } return; } rows.push(<ScoreItem score={scoreItem} key={scoreItem.id} />) }) return ( <table className="gridtable"> <thead> <tr> <th>姓名</th> <th>性别</th> <th>语文</th> <th>数学</th> </tr> </thead> <tbody> {rows} </tbody> </table> ); } } class ScoreItem extends React.Component{ constructor(props){ super(props); } render(){ let score=this.props.score; return ( <tr> <td>{score.name}</td> <td>{score.gender}</td> <td>{score.chinese}</td> <td>{score.math}</td> </tr> ); } } class GenderInputBar extends React.Component{ constructor(props){ super(props); this.genderChangeHandler=this.genderChangeHandler.bind(this); } genderChangeHandler(e){ eventProxy.trigger(GenderFilterChangeEvt,e.target.value); } render(){ return ( <div> <from> <label>按性别筛选:</label> <select onChange={this.genderChangeHandler}> <option value="0">All</option> <option value="1">男</option> <option value="2">女</option> </select> </from> </div> ); } } class NameInputBar extends React.Component{ constructor(props){ super(props); this.nameChangeHandler=this.nameChangeHandler.bind(this) } nameChangeHandler(e){ eventProxy.trigger(NameFilterChangeEvt,e.target.value); } render(){ return ( <div> <form> <label htmlFor="nameInput">按姓名筛选:</label> <input type="text" id="nameInput" value={this.props.nameFilter} onChange={this.nameChangeHandler} /> </form> </div> ); } } ReactDOM.render( <StudentScoreTable score={SCORE} />, document.getElementById("root")); </script>