react遍历对象的值_React 原理之实现 createElement 和 render 方法
前言
在 React 中,我们都知道可以写 jsx 代码会被编译成真正的 DOM 插入到要显示的页面上。这具体是怎么实现的,今天我们就自己动手做一下。
实现 createElement 方法
这个方法平时开发我们并不会用到,因为它是经 babel 编译后的代码,我们新建一个 React 项目,index.js 最简单的代码结构如下:
import React from 'react'import ReactDOM from 'react-dom'ReactDOM.render(<h1 className='title'>Hello Reacth1>, document.getElementById('root'))
这里就 jsx 会变编译成真正的 DOM ,把 html 代码拿到 babel 官网编译
于是我们就看到了 React.createElement() 方法,但这只是调用这个方法,它具体做了什么返回什么我们还不知道,我们可以打印这个函数运行的结果:
console.log( React.createElement( 'h1', { className: 'title', }, 'Hello React' ))
返回的这个对象就是虚拟 DOM 了。
我们来分析它返回的对象参数,首先第一个是
$$typeof: REACT_ELEMENT_TYPE
这个是 React 元素对象的标识属性
REACT_ELEMENT_TYPE 的值是一个 Symbol 类型,代表了一个独一无二的值。如果浏览器不支持 Symbol 类型,值就是一个二进制值。
❝
为什么是 Symbol?主要防止 XSS 攻击伪造一个假的 React 组件。因为 JSON 中是不会存在 Symbol 类型的。
❞
- key:这个比如循环中会用到这个 key 值
- props:传入的属性值,比如 id, className, style, children 等
- ref:DOM 的引用
- 剩下的是私有属性(本篇不展开讨论)
在本篇我们会用自己简单的方式实现这两个方法,而不是根据源码,所以实现上的方法只要能实现它的基本功能即可;有个基本概念在,以后再循序渐进学习源码。
而 createElement 中有三个参数,更确切说是 n 个参数:
- type:表示要渲染的元素类型。这里可以传入一个元素 Tag 名称,也可以传入一个组件(如 div span 等,也可以是是函数组件和类组件)
- props:创建 React 元素所需要的 props。
- childrens(可选参数):要渲染元素的子元素,这里可以向后传入 n 个参数。可以为文本字符串,也可以为数组
初步 createElement 方法:
// 创建 JSX 对象function createElement(type, props, ...childrens) { return { type, props: { ...props, children: childrens.length <= 1 ? childrens[0] || '' : childrens, },}
参数中 props 和 childrens 是并列关系,然后返回的 props 对象,里面包含了 children,所以我们需要再 props 里面添加 children 参数,然后根据 children 参数为一个或多个的可能在进行取值处理。
调用该方法:
console.log( createElement( 'h1', { className: 'title', }, 'Hello React' ))
除去其它本篇我们不讨论的属性,目前算是实现了一半;我们观察原来 React 自身方法输出的结果有 key, ref, 同输出的 props 也是并列关系,于是我们进一步作出处理
function createElement(type, props, ...childrens) { let ref, key if ('ref' in props) { ref = props['ref'] props['ref'] = undefined } if ('key' in props) { key = props['key'] props['key'] = undefined } return { type, props: { ...props, children: childrens.length <= 1 ? childrens[0] || '' : childrens, }, ref, key, }}
同样的方式调用结果如下:
如果添加多一些属性,我们来看看结果
console.log( createElement( 'div', { id: 'box', className: 'box', style: { color: 'red' }, key: '20' }, 'this is text', createElement('h2', { className: 'title' }, 'hello'), createElement('div', { className: 'content' }, 'Hi') ))
用了这种比较粗鲁的方式添加,设置为 undefined 在实现 render 方法的时候我们会根据这个忽略 props 内部的 key 和 props 属性,这里就实现了最基本的 createElement 方法了。
实现 render 方法
render 方法的第一个参数接收的是 createElement 返回的对象,也就是虚拟 DOM;第二个参数则是挂载的目标 DOM。同样的做法,我们用 babel 编译来看:
执行后,就被挂在到页面了
实现代码如下:
/* * 功能:把创建的对象生成对应的DOM元素,最后插入到页面中 * objJSX:createElement 返回的 JSX 对象 * container:挂载的容器,如 document.getElementById('root') */function render(objJSX, container) { let { type, props } = objJSX let newElement = document.createElement(type) for (let attr in props) { // 遍历传入的 props 属性 if (!props.hasOwnProperty(attr)) break // 不是私有的直接结束遍历 let value = props[attr] // >如果当前属性没有值,直接不处理即可 if (value == undefined) continue // NULL OR UNDEFINED
// 对几个特殊属性单独设置 switch (attr.toUpperCase()) { case 'ID': newElement.setAttribute('id', value) break case 'CLASSNAME': newElement.setAttribute('class', value) break case 'STYLE': // 传入的行内样式 style 是个对象,故需遍历赋值 for (let styleAttr in value) { if (value.hasOwnProperty(styleAttr)) { newElement['style'][styleAttr] = value[styleAttr] } } break case 'CHILDREN': /* * 可能是一个值:可能是字符串也可能是一个JSX对象 * 可能是一个数组:数组中的每一项可能是字符串也可能是JSX对象 */ // 首先把一个值也变为数组,这样后期统一操作数组即可 !(value instanceof Array) ? (value = [value]) : null value.forEach((item, index) => { // 验证ITEM是什么类型的:如果是字符串就是创建文本节点,如果是对象,我们需要再次执行RENDER方法,把创建的元素放到最开始创建的大盒子中 if (typeof item === 'string') { let text = document.createTextNode(item) newElement.appendChild(text) } else { render(item, newElement) } }) break default: newElement.setAttribute(attr, value) } } container.appendChild(newElement)}
❝
欢迎关注我掘金账号和Github技术博客:
- 掘金:https://juejin.im/user/1257497033714477
- Github:https://github.com/Jacky-Summer
- 觉得对你有帮助或有启发的话欢迎 star,你的鼓励是我持续创作的动力~
- 如需在微信公众号平台转载请联系作者授权同意,其它途径转载请在文章开头注明作者和文章出处。
❞
react遍历对象的值_React 原理之实现 createElement 和 render 方法相关推荐
- 使用 React 遍历对象
今天使用React完成一个小案例,使用react把数据渲染到页面,效果如下 首先,既然要是要使用react遍历对象吗,那我们就得引入react的相关插件引入,并且把我们要渲染到页面的data.js数据 ...
- 直接修改html文本页面没变化,VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法分析...
本文实例讲述了VUE 直接通过JS 修改html对象的值导致没有更新到数据中解决方法.分享给大家供大家参考,具体如下: 业务场景 我们在使用vue 编写 代码时,我们有一个 多行文本框控件,希望在页面 ...
- react 遍历对象_React 和 Vue 之间的相爱相杀
React 和 Vue 应该是国内当下最火热的前端框架,当然 Angular 也是一个不错的框架,但是这个产品国内使用的人很少再加上我对 Angular 也不怎么熟悉,所以就不在这篇文章中做对比了. ...
- react 遍历对象_React 源码系列 | React Children 详解
本文基于 React V16.8.6,本文代码地址 测试代码 源码讲解 React 中一个元素可能有 0 个.1 个或者多个直接子元素,React 导出的 Children 中包含 5 个处理子元素的 ...
- react 遍历对象_探索:跟随《Build your own React》实现一个简易React
文章介绍 build-your-own-react是一篇操作说明书,指导用户一步步实现一个简易的React,从中了解到React的大体工作流程.这篇文章是我的观后整理和记录,或许对大家会有所帮助. 构 ...
- react如何获取input值_react中怎么获取input的值?
react中怎么获取input输入框的值?下面本篇文章给大家介绍一下.有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助. react 获取input 输入框的值第一种方法:通过event ...
- js遍历对象key,value
声明一个对象: let obj = {name: 'Kamen',age: '23',hobby: 'eat eat eat'} 方法一:转化为操作数组forEach遍历 遍历对象属性 //遍历对象属 ...
- 关于javascript遍历对象
1:遍历对象属性var obj={a:'aa',b:'bb'} for(var i in obj) {alert(i); //输出 a b } var obj={'a':'aa','b':'bb'} ...
- react循环key值_React源码揭秘(三):Diff算法详解
编者按:本文作者奇舞团前端开发工程师苏畅. 代码参照React 16.13.1 什么是Diff 在前两篇文章中我们分别介绍了 React 的首屏渲染流程1和组件更新流程2,其中 首屏渲染会渲染一整棵 ...
最新文章
- 2018-3-21李宏毅机器学习视频笔记(十三)--“Hello Wrold” of Deep learning
- OpenCV中cvADDS()为啥第二个参数要是CvScalar类型?掩码mask=NULL又是何意?
- spring mvc DispatcherServlet详解之interceptor和filter的区别
- 10-Platform Interrupt Controller API
- Java源码解析:hashCode与相同对象的关系
- MacOS/MacBook设置短语快捷键
- 张娟娟(为奥运冠军名字作诗)
- linux如何自动化部署脚本实现免密登录并访问资源
- 在Ubuntu 18.04 LTS 入门 ROS Melodic 机器人 操作系统
- 【论文】Awesome Relation Extraction Paper(关系抽取)(PART IV)
- 【赠书活动】赠送清华社的《好好学Java:从零基础到项目实战》
- 语义分割和实例分割_2019 语义分割指南
- 程序员新电脑装机软件
- 宏基 4560G笔记本 AMD APU A6-3400试用报告
- 关于阿里云服务器租用费用的介绍
- 面向对象核心(继承)
- 颈椎病的康复锻炼方法
- Lan9252-FPGA调试笔记
- 袋鼠过河问题(DP)
- 数据结构课程大纲和教学设计
热门文章
- java的自增自减_Java中自增和自减操作符(++/--)的那些事
- unity怎么设置游戏页面_杭州有没有正规的unity游戏开发培训机构?
- 源码安装NASM,无root权限
- faster rcnn的测试
- c语言中for语句的作用是,c语言中for语句是怎么用的
- JAVA格式化当前日期或者取年月日
- AMBA总线协议AHB、APB
- 设△ABC的内角A,B,C,所对的边分别为a,b,c,且acosB-bcosA=3/5c,则tan(A-B)的最大值为
- 130242014022 蓝宏铮 第2次实验
- 2017.4.11 AM