This is the 12th day of my participation in Gwen Challenge
Let’s write a paragraph about JSX, which we won’t go into too much here, and then we’ll talk about JSX syntax
const ele = (
const ele = (
<div className="box" size="25">
hello <span>zidea</span>
</div>))Copy the code
Then use Babel to convert the above JSX to JS as follows
"use strict";
const ele = /*#__PURE__*/React.createElement("div", {
className: "box".size: "25"
}, "hello "./*#__PURE__*/React.createElement("span".null."zidea"));
Copy the code
Take a quick look at the generated code and analyze it briefly
React.createElement(tag,attrs,children)
Copy the code
- Tag is the name of the tag to be created
- Attrs organizes attribute objects in the form of objects that hold attribute names and values in key-value pairs
- Children are children
Implement the createElement method
- Create React object
const React = {
createElement
}
Copy the code
- Implement the creatElement method
// createElement
function createElement(tag,attrs,... children){
return {
tag,
attrs,
children
}
}
export default React;
Copy the code
- Introduce the React object and use the React createElement method
import React from './react'
const ele = (
<div className='title' title='react source analysis'>
hello <span>react</span>
</div>
)
console.log(ele)
Copy the code
Implement rendering
We all know how to render a virtual node to a page by calling the Render method of ReactDom in React and passing in the virtual node and adding the container DOM element to the virtual node.
ReactDOM.render(ele,document.querySelector("#root"))
Copy the code
import React from './react'
const ele = (
<div className='box' title='hello zidea'>
hello <span>react</span>
</div>
)
// console.log(ele)
ReactDOM.render(ele,document.querySelector("#root"))
Copy the code
The next step is to create a folder called react-dom and create an index.js file in that folder to implement the Render method of ReactDOM
const ReactDOM = {
render
}
function render(vnode,container){
//TODO
}
export default ReactDOM;
Copy the code
I won’t explain too much about a common JS module and exposing the ReactDOM object. Let’s focus on the render method implementation.
Text node implementation
function render(vnode,container){
//TODO
if(vnode === undefined ) return;
// vnode is equal string
if(typeof vnode === 'string') {//create textNode
const textNode = document.createTextNode(vnode)
return container.appendChild(textNode)
}
}
Copy the code
- The react argument is no different, okay
- Vnode Virtual node
- The container vessel
- It is preferred to check whether the VNode is empty or return if the vNode is empty
- Then determine if vNode is a string, and if it is a string, add a text node
ReactDOM.render('react'.document.querySelector("#root"))
Copy the code
Virtual node
ReactDOM.render(ele,document.querySelector("#root"));
Copy the code
console.log(vnode)
Copy the code
function render(vnode,container){...// deconstruct vnode
const {tag} = vnode;
//create dom object
const dom = document.createElement(tag)
container.appendChild(dom)
}
Copy the code
- Deconstruct the VNode object
- Create dom objects based on the tag
- Add the DOM object to the container
Retrieve attributes
function render(vnode,container){...// deconstruct vnode
const {tag,attrs} = vnode;
//create dom object
const dom = document.createElement(tag)
if(attrs){
// property key: className box
Object.keys(attrs).forEach(key= >{
const val = attrs[key]
})
}
...
}
Copy the code
- Deconstruct attrs from virtual nodes (VNodes)
- Attrs is then iterated to get the attribute value
Set properties
function setAttribute(dom,key,value){}Copy the code
Implement the setAttribute method
function setAttribute(dom,key,value){
// convert className to class
// 1. event 2.class 3.style etc
// class case
if(key === 'className'){
key = 'class'
}
// event case
if(/on\w+/.test(key)){
//to lower case
key = key.toLowerCase();
dom[key] = value || ' '
}else if(key === 'style') {if(! value ||typeof value === 'string'){
dom.style.cssText = value || ' ';
}else if(value && typeof value === 'object') {//{width:16}
for(let k in value){
if(typeof value[k] === 'number'){
dom.style[k] = value[k] + 'px'
}else{
dom.style[k] = value[k]
}
}
}
}else{
if(key in dom){
dom[key] = value || ' '
}
if(value){
dom.setAttribute(key,value)
}else{
dom.removeAttribute(key)
}
}
}
Copy the code
There are many properties in the DOM that you can use to add styles, add events, save data, and so on. We do this by determining the attribute key and value type in attrs
The class attribute
If the key is className, we will change the key to class while adding the value
if(key === 'className'){
key = 'class'
}
Copy the code
Event attributes
if(/on\w+/.test(key)){
//to lower case
key = key.toLowerCase();
dom[key] = value || ' '
}
Copy the code
Style properties
else if(key === 'style') {if(! value ||typeof value === 'string'){
dom.style.cssText = value || ' ';
}else if(value && typeof value === 'object') {//{width:16}
for(let k in value){
if(typeof value[k] === 'number'){
dom.style[k] = value[k] + 'px'
}else{
dom.style[k] = value[k]
}
}
}
}
Copy the code
The style case is a little more complicated than the other attributes and can be handled in two ways: a string or an object
- In the case of strings, the assignment is straightforward
- Object is
To start working with objects, let’s take a look at the following JSX objects compiled as javascript objects by default
const ele = (
<div className="box" size="25" style={{width:16}}>
hello <span>zidea</span>
</div>
)
Copy the code
.style: {
width: 16}...Copy the code
Here an object is nested within the Style object, and we parse the object to get the name and style value of each style. The style value can be a numeric value or a string.
for(let k in value){
if(typeof value[k] === 'number'){
dom.style[k] = value[k] + 'px'
}else{
dom.style[k] = value[k]
}
}
Copy the code
if(attrs){
// property key: className box
Object.keys(attrs).forEach(key= >{
const val = attrs[key]
setAttribute(dom,key,val)
})
}
container.appendChild(dom)
Copy the code
Render child node
The child nodes are rendered recursively
function render(vnode,container){... vnode.children.forEach(child= >render(child,dom))
container.appendChild(dom)
}
Copy the code