react-创建react元素
前言
react 元素,即JSX语法。
const Nav, Profile;
// 输入(JSX):
const app = <Nav color="blue"><Profile>click</Profile></Nav>;
// 经过react编译解释之后,输出(JavaScript):
const app = React.createElement(
Nav,
{color:"blue"}, React.createElement(Profile, null, "click")
);
可以看到,我们平时在react 中写的语法,最终是调用React的createElement方法。
那么createElement做了什么呢?
直接查看源码,一探究竟。
实现步骤
- 获取react 内部的 key , ref
- 从props 上获取self, source,和其他属性
- 获取children ,如果是有多个children ,需要freeze 住
- 从type的defaultProps中填充缺失的属性
- 如果是开发环境,并且key 或 ref 存在,需要定义添加warning 信息
- 返回一个ReactElement 对象
好,开始实现
React.createElement = function(type, config, children) {
var propName;
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
if (config !== null) {
if (hasValidKey(config)) {
key = '' + config.key;
}
if (hasValidRef(config)) {
ref = config.ref;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
for(propName in config) {
if (hasOwnerProperty.call(config, propName) && !REACT_RESERVED_PROPS.hasOwnProperty(propName) {
props[propName] = config[propName];
}
}
// children
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
var childArray = Array(childrenLength);
for(var i = 0 ; i < childrenLength ; i++) {
childArray[i] = arguments[ i + 2 ];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
// default Props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for(propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
// key || ref
if (__DEV__) {
if (key || ref) {
if (typeOf config.$$typeOf === undefined || props.$$typeOf !== REACT_ELEMENT_TYPE) {
var displayName = typeOf type === 'function' ? type.displayName || type.name || 'Unknown'
: type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props
);
};
在上述代码中可以看到,createElement 最终返回的是一个ReactElement 对象,那ReactElement又是什么对象呢?
实现步骤:
- 设置react特殊标志的属性
- 设置element 基本属性
- 开发环境下,添加适用于开发环境的属性
ReactElement = function(type, key, ref, self, source, owner, props) {
var element = {
$$typeOf: REACT_ELEMENT_TYPE,
type: type,
key: key,
ref: ref,
// record the component responsible for creating the element
_owner: owner,
};
if (__DEV__) {
// self && source only dev props
element._store = {};
Object.defineProperty(element._store, 'validated', {
writable: false,
configurable: false,
enumerable: false,
value: false,
});
Object.defineProperty(element, '_self', {
writable: false,
configurable: false,
enumerable: false,
value: self,
});
Object.defineProperty(element, '_source', {
writable: false,
configurable: false,
enumerable: false,
value: source,
});
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}
}
return element;
}
其中校验key 和 self 是否是有效的方法为:
(因为两种是相似的,所以只列出一种)
var defineKeyPropWarningGetter = function(props, displayName) {
var warnAboutAccessingKey = function() {
if (!specialPropKeyWarningShown) {
specialPropKeyWarningShow = true;
warn(false,
'%s, `ref` prop 。。。。', displayName);
}
}
warnAboutAccessingKey.isReactWarning = true;
Object.defineProperty(props, 'key', {
get: warnAboutAccessingKey
configurable: true,
})
};
var hasValidKey = function(config) {
if (__DEV__) {
if (hasOwnerProperty.call(config, 'key')) {
var getter = Object.getOwnPropertyDescriptor(config, 'key').get;
if (getter && getter.isReactWarning) {
return false;
}
}
}
return config.key !== undefined;
}
其他一些定义:
var REACT_ELEMENT_TYPE = (typeOf symbol && symbol.for && symbol.for('react.element')) || 0xeac7;
/**
* Keeps track of the current owner.
*
* The current owner is the component who should own any components that are
* currently being constructed.
*/
var ReactCurrentOwner = {
current: (null: null | ReactInstance | Fiber) // 这是什么写法???
}
var REACT_RESERVED_PROPS = {
key: true,
ref: true,
__self: true,
__source: true,
};
参考文献:
react源码:/16.0.0-rc.2/src/isomorphic/classic/element/ReactElement.js
陈屹:《深入react技术栈》
react-创建react元素的更多相关文章
- React 深入系列1:React 中的元素、组件、实例和节点
文:徐超,<React进阶之路>作者 授权发布,转载请注明作者及出处 React 深入系列,深入讲解了React中的重点概念.特性和模式等,旨在帮助大家加深对React的理解,以及在项目中 ...
- React + TypeScript:元素引用的传递
React 中需要操作元素时,可通过 findDOMNode() 或通过 createRef() 创建对元素的引用来实现.前者官方不推荐,所以这里讨论后者及其与 TypeScript 结合时如何工作. ...
- react创建组件的几种方式及其区别
react创建组件有如下几种方式 ①.函数式定义的无状态组件 ②.es5原生方式React.createClass定义的组件 ③.es6形式的extends React.Component定义的组 ...
- React创建组件的不同方式(ES5 & ES6)
一. 首先缕清楚React.createElement.React.createClass.React.Component之间的关系 1. React.createElement(HTML eleme ...
- React创建组件的三种方式及其区别
内容转载于http://www.cnblogs.com/wonyun/p/5930333.html React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: ...
- React创建组件的方法,组件的props属性、state属性的用法和特点,父子组件传值,兄弟组件传值
创建组件的方法,组件的props属性.state属性的用法和特点,父子组件传值,兄弟组件传值 1.react组件 1.1.创建组件的方法 1.1.1.函数组件 定义一个组件最简单的方式是使用JavaS ...
- 谈一谈创建React Component的几种方式
当我们谈起React的时候,多半会将注意力集中在组件之上,思考如何将页面划分成一个个组件,以及如何编写可复用的组件.但对于接触React不久,还没有真正用它做一个完整项目的人来说,理解如何创建一个组件 ...
- React(一)使用脚手架创建React项目
1.安装脚手架 现在使用较多的就是这三种脚手架工具: react-boilerplate react-redux-starter-kit create-react-app 我使用的是第三种,faceb ...
- react创建项目很慢,最后提示fetch failed的解决方法
$ cnpm install -g create-react-app //创建react全局变量 $ create-react-app my-app //创建一个react项目 国内使用 npm 速度 ...
- 创建react项目的几种方法
前言: 构建React项目的几种方式: 构建:create-react-app 快速脚手架 构建:generator-react-webpack 构建:webpack一步一步构建 1)构建:creat ...
随机推荐
- 第五章 绘图基础(DEVCAPS1)
获取设备环境的信息 //DEVCAPS1.C--Device Capabilities Display Program No.1 (c) Charles Petzold, 1998 #include ...
- 【PAT】B1002 写出这个数
思路: 1.以字符串形式输入数据,计算结果 2.使用sprintf将结果数字转换为字符串(将数字每一位分开) 3.分别输出字符每一位 1,笨方法,用的ifelse来判断输出 #include<s ...
- ASP.NET WebForm 检测页面刷新(Refresh)
本文是翻译贴, 原文参见Detecting browser 'Refresh' from Code behind in C# 浏览器的"刷新"常会导致问题, 特别是当页面和数据库有 ...
- 【Ansible 文档】提示、推荐、注意事项
1. 查看 详细 信息 如果你想要查看成功模块和不成功的详细输出,使用 --verbose 标识 2. 检查 playbook 的语法 使用 ansible-playbook 的 --syntax-c ...
- 手把手实战:eclipse 搭建 SpringMvc 框架环境
环境准备 eclipse jdk1.8 tomcat 7 步骤总纲 a.准备好开发环境 b.下载相关jar包 c.在eclipse 中创建好工程 d.引进下载的ja ...
- exec dbms_stats.gather_schema_stats 手动优化统计
Oracle10g或以上版本.exec dbms_stats.gather_schema_stats(ownname => 'DFMS', options => 'GATHER AUTO' ...
- Linux(CentOS)上配置 SFTP(附解决Write failed: Broken pipe Couldn't read packet: Connection reset by peer)
#创建sftp组: groupadd sftp #创建一个用户sftpuser: useradd -g sftp -s /bin/false sftpuser #提示: /etc/group 文件包含 ...
- 20145203盖泽双 《网络对抗技术》实践1—— MAL_逆向与Bof基础
20145203盖泽双 <网络对抗技术> MAL_逆向与Bof基础 实践目标 (1)我们要通过修改程序代码,使得程序运行其自身中本不该运行的代码片段. (2)在这里,我们有一个名为2014 ...
- 转载 AutoMapper在C#中的有趣应用 https://www.cnblogs.com/lvlinlv/p/7344916.html
最近发现了一个比较有趣的东西 AutoMapper,主要将Model转换为DTO,DTO更注重数据,对领域对象进行合理封装,从而不会将领域对象的行为过分暴露给表现层. 先来看一点实例,两个类之间的映射 ...
- WEB安全 - 认识与防御XSS攻击
目录 什么是xss攻击? XSS的危害 XSS攻击分类 xss攻击示例 反射型攻击 - 前端URL参数解析 反射型攻击 - 后端URL参数解析 注入型攻击 - 留言评论 如何规避xss攻击? 总结 什 ...