
看到这个api想必大家再熟悉不过了,平常我们在react开发过程中写的组件都是继承自这个Component组件,比如我们在声明ClassComponent的时候extends的就是ReactComponent,在看源码只是我个人觉得写个class应该实现了很多复杂的功能比如说setState和render方法等,但是看了源码之后颠覆了我之前的认知: Component
在源码中Component方法只是简单的对props和context进行了赋值 *** 作,这两个传入的参数我们都很熟悉,最后这个updater参数我们我们接触到。通过源码我们看到在Component的原型上声明了setState方法:
该函数内部只是判断了传入参数的合法性最后调用了Component中updater方法上的enqueueSetState。然后方法结束,这里去查了一下资料,这个方法具体的实现是在react-dom中完成的。为什么要这样做呢,因为在react中只是简单的提供了这个方法的入口,具体的调用需要看你在哪个平台下使用,比如在react-dom中和在react-native中的调用肯定是不同的。在原型上也声明了:
// forceUpdate-强制更新组件State方法
看到这里我们发现只是调用了updater 的enqueueForceUpdate方法,个人认为跟字面意思一样,对state的进行了强制更新 *** 作。PureComponent的用法我们不必再去赘述,该方法实际就是对Component方法进行了继承,但是多加了一个属性:
// 在原型上添加一个额外的isPureReactComponent属性/,标识是一个pureComponent
isPureReactComponent用来说明是一个PureComponent。最后将这两个方法导出,到这里我们有关Componet的源码已经完结了,我们看到在react中其实没有太多复杂的 *** 作,只是对传入参数的赋值,已经留下了一些函数入口。像更新渲染等 *** 作实际都放在了react-dom中去完成。
在开发中我们通常会有这样的需求,有时候我们需要获取某个Dom节点或者拿到classComponent类型的子组件的实例,进而 *** 作这个子组件。比如说我们需要通过在父级组件中调用到子组件中的方法,从而更新子组件,这里的更新就不仅仅局限于更新props,通常我们跟新props也不需要获得子组件的实例。 这里通过ref这个属性会让我们很容易 *** 作子组件。
一般在现有版本中有三种使用ref的方法:
(1)string 类型ref ref="string" == {不推荐,下个大版本会废弃}
(2)function类型 ref = {ele => (thischildRef = ele )}
(3)ReactcreateRef()
大致用法类似于这个样子,需要注意的是我们在使用ref时候,如果目标组件是一个function类型的Component一般来说这个时候拿到的ref肯定是undefined,因为functionComponent是没有实例的,后面我们会介绍一个叫做forward-ref的属性,这个属性可以让我们取到函数类型组件上去使用ref。接下来我们去看看createRef方法的源码: createRef
这里的源码很简单只是创建了一个refObject在上面声明了一个为null的currenrt属性。然后将这个对象返回。其实这个源码看到这里也看不出ref到底是怎么挂载在组件的this上面的。这里应该是在react更新的过程中实现的,react中只有更新到结束一个完整的流程,至于到底是怎么挂载的ref我们接着往下读。
了解更多: react-source-code
子组件使用了 Formcreate()如何让父组件调用子组件的方法
在写react技术栈使用ant design时 Form的使用会带来一个问题,会导致你无法直接使用refs去调用使用Form的子组件自定义方法。当你调用时会抛出异常。
子组件写有Form表单父组件使用thisrefsrefNamemychild是获取不到该方法的;
说说React
一个组件,有自己的结构,有自己的逻辑,有自己的样式,会依赖一些资源,会依赖某些其他组件。比如日常写一个组件,比较常规的方式:
- 通过前端模板引擎定义结构
- JS文件中写自己的逻辑
- CSS中写组件的样式
- 通过RequireJS、SeaJS这样的库来解决模块之间的相互依赖,
那么在React中是什么样子呢?
结构和逻辑
在React的世界里,结构和逻辑交由JSX文件组织,React将模板内嵌到逻辑内部,实现了一个JS代码和HTML混合的JSX。
结构
在JSX文件中,可以直接通过 ReactcreateClass 来定义组件:
var CustomComponent = ReactcreatClass({
render: function(){
return ();
}
});
通过这种方式可以很方便的定义一个组件,组件的结构定义在render函数中,但这并不是简单的模板引擎,我们可以通过js方便、直观的 *** 控组件结构,比如我想给组件增加几个节点:
var CustomComponent = ReactcreatClass({
render: function(){
var $nodes = ['h','e','l','l','o']map(function(str){
return ({str});
});
return ({$nodes});
}
});
通过这种方式,React使得组件拥有灵活的结构。那么React又是如何处理逻辑的呢?
逻辑
写过前端组件的人都知道,组件通常首先需要相应自身DOM事件,做一些处理。必要时候还需要暴露一些外部接口,那么React组件要怎么做到这两点呢?
事件响应
比如我有个按钮组件,点击之后需要做一些处理逻辑,那么React组件大致上长这样:
var ButtonComponent = ReactcreateClass({
render: function(){
return (屠龙宝刀,点击就送);
}
});
点击按钮应当触发相应地逻辑,一种比较直观的方式就是给button绑定一个 onclick 事件,里面就是需要执行的逻辑了:
function getDragonKillingSword() {
//送宝刀
}
var ButtonComponent = ReactcreateClass({
render: function(){
return (屠龙宝刀,点击就送);
}
});
但事实上 getDragonKillingSword() 的逻辑属于组件内部行为,显然应当包装在组件内部,于是在React中就可以这么写:
var ButtonComponent = ReactcreateClass({
getDragonKillingSword: function(){
//送宝刀
},
render: function(){
return (屠龙宝刀,点击就送);
}
});
这样就实现内部事件的响应了,那如果需要暴露接口怎么办呢?
暴露接口
事实上现在 getDragonKillingSword 已经是一个接口了,如果有一个父组件,想要调用这个接口怎么办呢?
父组件大概长这样:
var ImDaddyComponent = ReactcreateClass({
render: function(){
return (
//其他组件
//其他组件
);
}
});
那么如果想手动调用组件的方法,首先在ButtonComponent上设置一个 ref="" 属性来标记一下,比如这里把子组件设置成 ,那么在父组件的逻辑里,就可以在父组件自己的方法中通过这种方式来调用接口方法:
thisrefsgetSwordButtongetDragonKillingSword();
看起来屌屌哒~那么问题又来了,父组件希望自己能够按钮点击时调用的方法,那该怎么办呢?
配置参数
父组件可以直接将需要执行的函数传递给子组件:
然后在子组件中调用父组件方法:
var ButtonComponent = ReactcreateClass({
render: function(){
return (屠龙宝刀,点击就送);
}
});
子组件通过 thisprops 能够获取在父组件创建子组件时传入的任何参数,因此 thisprops 也常被当做配置参数来使用
屠龙宝刀每个人只能领取一把,按钮点击一下就应该灰掉,应当在子组件中增加一个是否点击过的状态,这又应当处理呢?
组件状态
在React中,每个组件都有自己的状态,可以在自身的方法中通过 thisstate 取到,而初始状态则通过 getInitialState() 方法来定义,比如这个屠龙宝刀按钮组件,它的初始状态应该是没有点击过,所以 getInitialState 方法里面应当定义初始状态 clicked: false 。而在点击执行的方法中,应当修改这个状态值为 click: true :
var ButtonComponent = ReactcreateClass({
getInitialState: function(){
//确定初始状态
return {
clicked: false
};
},
getDragonKillingSword: function(){
//送宝刀
//修改点击状态
thissetState({
clicked: true
});
},
render: function(){
return (屠龙宝刀,点击就送);
}
});
这样点击状态的维护就完成了,那么render函数中也应当根据状态来维护节点的样式,比如这里将按钮设置为 disabled ,那么render函数就要添加相应的判断逻辑:
render: function(){
var clicked = thisstateclicked;
if(clicked)
return (屠龙宝刀,点击就送);
else
return (屠龙宝刀,点击就送);
}
小节
这里简单介绍了通过JSX来管理组件的结构和逻辑,事实上React给组件还定义了很多方法,以及组件自身的生命周期,这些都使得组件的逻辑处理更加强大
资源加载
CSS文件定义了组件的样式,现在的模块加载器通常都能够加载CSS文件,如果不能一般也提供了相应的插件。事实上CSS、可以看做是一种资源,因为加载过来后一般不需要做什么处理。
React对这一方面并没有做特别的处理,虽然它提供了Inline
Style的方式把CSS写在JSX里面,但估计没有多少人会去尝试,毕竟现在CSS样式已经不再只是简单的CSS文件了,通常都会去用Less、
Sass等预处理,然后再用像postcss、myth、autoprefixer、cssmin等等后处理。资源加载一般也就简单粗暴地使用模块加载器
完成了
组件依赖
组件依赖的处理一般分为两个部分:组件加载和组件使用
组件加载
React没有提供相关的组件加载方法,依旧需要通过
以上就是关于【原创】react-源码解析 - Component&Ref(3)全部的内容,包括:【原创】react-源码解析 - Component&Ref(3)、react 使用ant design UI 父组件this.refs无法调用子组件自定的方法、react在组件哪个生命周期可以拿到this.props等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)