zl程序教程

您现在的位置是:首页 >  工具

当前栏目

React中父子组件间的通信问题

组件React通信 父子 问题
2023-09-27 14:28:55 时间

一 组合而不是继承


React组件是无法继承的,即不存在 React.extend 之类的方法可以定义一个子类。
React推崇通过组合的方式来组织大规模的应用。
所以所谓父子组件,就和DOM中的父子元素一样,他们是有从属关系,但没有继承关系。
比如:

[javascript]  view plain  copy
  1. var Team = React.createClass({  
  2. render: function() {  
  3. return <div>Team onwer is: <People name={this.props.name}></People></div>;  
  4. }  
  5. });  
  6. var People = React.createClass({  
  7. render: function() {  
  8. return <span>{this.props.name}</span>;  
  9. }  
  10. });  
  11.   
  12. React.render(  
  13. <Team name='Lucy' />,  
  14. document.getElementById('example')  
  15. );  




我们有一个父组件 Team,里面有一个子组件 People。
Team和People并不存在谁继承谁,只是 People 组成了 Team 而已。

大家都知道面向对象三个特性:封装、继承和多态。其中继承当然不是错的,但是确是争议最大的一个。可以参见这篇文章: http://blog.berniesumption.com/software/inheritance-is-evil-and-must-be-destroyed/

很多时候,继承是可以通过interface之类的方式来完成的。

二 父子组件通信


组合起来很简单,那么父子组件怎么通信呢。
你可能会想通过事件来通信。React 竟然没有提供一个自定义事件,它的事件仅仅用来处理DOM事件,并没有组件的自定义事件。
比如一个子组件是无法通过 trigger(“hungry”) 之类的事件来通知父组件的。当然,你可以通过mixin之类的方式来给组件提供事件能力。
那么这样,就只有一种方式可以让子组件向父组件发送消息,就是 this.props 属性。
比如 父组件需要知道子组件的 hungry 事件,那么他向子组件传递一个 props.onHungry 方法。这样子组件通过调用 this.props.onHungry 就可以通知父组件。

而父组件怎么通知子组件呢?
也是通过 props,直接 setProps 来修改子组件的 props就行了。

这样,实际上 props 是父子组件通信的最重要的甚至是唯一的标准渠道。

看一个例子,还是上面的例子,稍作改动:

[html]  view plain  copy
  1. var Team = React.createClass({  
  2. onHungry: function(name) {  
  3. alert(name + " is hungry");  
  4. },  
  5. render: function() {  
  6. return <div>Team onwer is: 
  7. <People name={this.props.name} onHungry={this.onHungry}>
  8. </People></div>;  
  9. }  
  10. });  
  11. var People = React.createClass({  
  12. render: function() {  
  13. return <span onClick={this.handleClick}>{this.props.name}</span>;  
  14. },  
  15. handleClick: function() {  
  16. this.props.onHungry(this.props.name);  
  17. }  
  18. });  
  19.   
  20. var team = React.render(  
  21. <Team name='Lucy' />,  
  22. document.getElementById('example')  
  23. );  



点一下 Lucy 就会alert一下。
Team 组件通过 props.onHungry 传给了 People 组件一个回调,这样 People 组件就通过调用这个方法来通知Team。
这是子组件向父组件发送消息的方式。

那么父组件怎么向子组件发送消息呢。更简单了,直接修改 props  就行了

team.setProps({name: “Lily”})

因为 props 是父子组件的通信渠道,为了避免状态不一致,所以严格杜绝组件修改自己的状态。
可以通过 team.setProps 方式修改,这属于组件外修改,但是不能在组件中 通过 this.setProps 方式来修改。

那么现在有一个问题,React是如何知道一个组件的 props 被他的父组件修改了?
我们把上面的代码改一下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. var Team = React.createClass({  
  2. getInitialState: function() {  
  3. return {  
  4. name: "Lucy"  
  5. }  
  6. },  
  7. onHungry: function(name) {  
  8. alert(name + " is hungry");  
  9. },  
  10. render: function() {  
  11. return <div onMouseOver={this.onMouseOver} onMouseOut={this.onMouseOut}>
  12. Team onwer is: <People {...this.state} onHungry={this.onHungry}></People></div>;  
  13. },  
  14. onMouseOver: function() {  
  15. this.setState({  
  16. name: "mouseOver"  
  17. });  
  18. },  
  19. onMouseOut: function() {  
  20. this.setState({  
  21. name: "mouseOut"  
  22. });  
  23. }  
  24. });  
  25. var People = React.createClass({  
  26. render: function() {  
  27. return <span onClick={this.handleClick}>{this.props.name}</span>;  
  28. },  
  29. handleClick: function() {  
  30. this.props.onHungry(this.props.name);  
  31. }  
  32. });  
  33.   
  34. var team = React.render(  
  35. <Team name='Lucy' />,  
  36. document.getElementById('example')  
  37. );  


这样,Team把  this.state.name 作为 props 传给了 People 。
Team每次通过 this.setState 来修改state.name 的时候,People都会进行更新。
猜测是 setState 和 setProps 这两个方法会触发组件的更新。并且会触发每一个子组件检查更新。
子组件调用父组件:
1)在父组件设置对应的属性和方法;
2)将父组件的属性,方法设置在子组件的标签属性上;
3)子组件中利用this.props来调用父组件的成员;
eg:
父:

   var p=React.cleateClass({
     	getDefaultProps:function(){
       		return{
       			a:1
       		}
     	},
     	render:function(){
       		return <Ch a={this.props.a}></Ch>
     	}
	})

子:
   var Ch=React.createClass({
   		render:fucntion(){
     		 return <div>{this.props.a}</div>
   		}
	})

父组件调用子组件:
1)在父组件中的子组件利用ref对子组件标注引用;
2)在父组件中利用this,refs获取子组件的引用,从而调用子组件的成员;
eg:
父:
   var p=React.cleateClass({
        hand:function(){
       		this.refs.one.hands();
        },
     	render:function(){
       		return <Ch ref="one"></Ch>
		}
	})

子:
    var Ch=React.createClass({
  		hands:function(){}
  		render:fucntion(){
     		 return <div></div>
   		}
	})

【react】父组件向子组件传值


父向子是用props,然后再子那边有一个监听函数
[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. componentWillReceiveProps:function(nextProps){  
  2.         this.setState({  
  3.             visible:nextProps.visible,  
  4.             item:nextProps.item,  
  5.             value:nextProps.value,  
  6.             version:nextProps.version  
  7.         });  
  8.     },  

父类调用子类的函数
[javascript]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1.   
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html>  
  3. <head lang="en">  
  4.     <meta charset="UTF-8">  
  5.     <title></title>  
  6.     <script src="../../dist/react/react.js"></script>  
  7.     <script src="../../dist/react/JSXTransformer.js"></script>  
  8.     <script src="../../dist/jquery/jquery.min.js"></script>  
  9.     <!--如下的这种引用方式是不正确的,必须使用上面的引用方式-->  
  10.     <!--<script src="../../dist/react/JSXTransformer.js"/>-->  
  11. </head>  
  12. <body>  
  13.   
  14. <div id="index-0331-0011"></div>  
  15. <script type="text/jsx">  
  16.     var ButtonComment = React.createClass({  
  17.         getInitialState: function () {  
  18.             return {count:0};  
  19.         },  
  20.   
  21.         sendSword: function () {  
  22.             var newCount = this.state.count + 1;  
  23.             this.setState({count:this.state.count + 1});  
  24.             this.props.getSwordCount();  
  25.         },  
  26.   
  27.        render: function () {  
  28.            return (  
  29.                 <button onClick={this.sendSword}>{this.props.buttonName}</button>  
  30.            );  
  31.        }  
  32.     });  
  33.   
  34.     var ImDaddyComponent = React.createClass({  
  35.         getInitialState: function () {  
  36.             return {sendCount:0};  
  37.         },  
  38.         sendSword: function () {  
  39.             this.refs.getSwordButton.sendSword();  
  40.         },  
  41.         getSwordCount: function () {  
  42.             this.setState({sendCount:this.refs.getSwordButton.state.count + 1});  
  43.         },  
  44.         render: function () {  
  45.             return (  
  46.                 <div>  
  47.                     <ButtonComment ref="getSwordButton" getSwordCount={this.getSwordCount} buttonName="儿子送宝刀"/>  
  48.                     <button onClick={this.sendSword}>通过老爸送宝刀</button>  
  49.                     <p>  
  50.                         父子俩共送{this.state.sendCount}把宝刀!!!  
  51.                     </p>  
  52.                 </div>  
  53.             );  
  54.         }  
  55.     });  
  56.   
  57.     React.render(  
  58.             <ImDaddyComponent />,  
  59.             document.getElementById('index-0331-0011')  
  60.     );  
  61. </script>  
  62. </body>  
  63. </html>  





【react】子组件向父组件传值

reactjs是一枚新进小鲜肉,跟gulp搭配流行一段时间了。工作或者面试中经常遇到这样的问题,“子组件如何向父组件传值?”。其实很简单,概括起来就是:React中state改变了,组件才会update。父写好state和处理该state的函数,同时将函数名通过props属性值的形式传入子,子调用父的函数,同时引起state变化。子组件要写在父组件之前。具体写法看下面3个例子。

例子1.这里如下图,用户邮箱为父,绿色框为子。 父组件为用户输入的邮箱设好state,即“{email: ''}”,同时写好处理state的函数,即“handleEmail”,这两个名称随意起;再将函数以props的形式传到子组件,子组件只需在事件发生时,调用父组件传过来的函数即可。 

//以下所有例子对应的html
<body>
    <div id="test"></div>
</body>
复制代码
//子组件
var Child = React.createClass({
    render: function(){
        return (
            <div>
                请输入邮箱:<input onChange={this.props.handleEmail}/>
            </div>
        )
    }
});
//父组件,此处通过event.target.value获取子组件的值
var Parent = React.createClass({
    getInitialState: function(){
        return {
            email: ''
        }
    },
    handleEmail: function(event){
        this.setState({email: event.target.value});
    },
    render: function(){
        return (
            <div>
                <div>用户邮箱:{this.state.email}</div>
                <Child name="email" handleEmail={this.handleEmail}/>
            </div>
        )
    }
});
React.render(
  <Parent />,
  document.getElementById('test')
);
复制代码

例子2.有时候往往需要对数据做处理,再传给父组件,比如过滤或者自动补全等等,下面的例子对用户输入的邮箱做简单验证,自动过滤非数字、字母和"@."以外的字符。

复制代码
//子组件,handleVal函数处理用户输入的字符,再传给父组件的handelEmail函数
var Child = React.createClass({
    handleVal: function() {
        var val = this.refs.emailDom.value;
        val = val.replace(/[^0-9|a-z|\@|\.]/ig,"");
        this.props.handleEmail(val);
    },
    render: function(){
        return (
            <div>
                请输入邮箱:<input ref="emailDom" onChange={this.handleVal}/>
            </div>
        )
    }
});
//父组件,通过handleEmail接受到的参数,即子组件的值
var Parent = React.createClass({
    getInitialState: function(){
        return {
            email: ''
        }
    },
    handleEmail: function(val){
        this.setState({email: val});
    },
    render: function(){
        return (
            <div>
                <div>用户邮箱:{this.state.email}</div>
                <Child name="email" handleEmail={this.handleEmail}/>
            </div>
        )
    }
});
React.render(
  <Parent />,
  document.getElementById('test')
);
复制代码

例子3.如果还存在孙子组件的情况呢?如下图,黑框为父,绿框为子,红框为孙,要求子孙的数据都传给爷爷。原理一样的,只是父要将爷爷对孙子的处理函数直接传下去。

复制代码
//孙子,将下拉选项的值传给爷爷
var Grandson = React.createClass({
    render: function(){
        return (
            <div>性别:
                <select onChange={this.props.handleSelect}>
                    <option value="">男</option>
                    <option value="">女</option>
                </select>
            </div>
        )
    }
});
//子,将用户输入的姓名传给爹  
//对于孙子的处理函数,父只需用props传下去即可
var Child = React.createClass({
    render: function(){
        return (
            <div>
                姓名:<input onChange={this.props.handleVal}/>
                <Grandson handleSelect={this.props.handleSelect}/>
            </div>
        )
    }
});
//父组件,准备了两个state,username和sex用来接收子孙传过来的值,对应两个函数handleVal和handleSelect
var Parent = React.createClass({
    getInitialState: function(){
        return {
            username: '',
            sex: ''
        }
    },
    handleVal: function(event){
        this.setState({username: event.target.value});
    },
    handleSelect: function(event) {
        this.setState({sex: event.target.value});
    },
    render: function(){
        return (
            <div>
                <div>用户姓名:{this.state.username}</div>
                <div>用户性别:{this.state.sex}</div>
                <Child handleVal={this.handleVal} handleSelect={this.handleSelect}/>
            </div>
        )
    }
});
React.render(
  <Parent />,
  document.getElementById('test')
);