摘要:語法糖是一種的語法拓展,可以使用它來進行的展示我們一般會在組件的方法里使用進行布局和事件綁定的核心機制之一就是可以創(chuàng)建虛擬的元素,利用虛擬來減少對實際的操作從而提升性能,正是為了虛擬而存在的語法糖我們在平時的組件編寫中,通常都這么寫然而代碼
React.createElement語法糖
JSX是一種JavaScript的語法拓展,可以使用它來進行UI的展示:
const element =Hello, world!
;
我們一般會在組件的render方法里使用JSX進行布局和事件綁定:
class Home extends Component { render() { return (console.log("hello")}>); } }Hello, world!
React的核心機制之一就是可以創(chuàng)建虛擬的DOM元素,利用虛擬DOM來減少對實際DOM的操作從而提升性能,JSX正是為了虛擬DOM而存在的語法糖
我們在平時的組件編寫中,通常都這么寫:
import React, { Component } from "react"; class Demo extends Component { render() { return (Hello, world!
) } }
然而代碼里面并沒有用到React,為什么要引入這個變量呢?
因為JSX是React.createElement這個方法的語法糖:
const element =Hello
; // 等價于 const element = React.createElement("h1", { id: "container", className: "home" }, "Hello");
推薦大家在babeljs.io上看下JSX編譯后的實際效果
React.createElement有三個參數(shù):
React.createElement( type, // dom類型,比如div,h1 [props], // dom屬性,比如id,class,事件 [...children] // 子節(jié)點,字符串或者React.createElement生成的一個對象 )
JSX用一種類似HTML的語法替代了比較繁瑣的React.createElement純JS方法,而@babel/preset-react插件就起到了最關(guān)鍵的一步:負責(zé)在webpack編譯時,把所有的JSX都改成React.createElement:
class Home extends Component { render() { return (console.log("hello")}>); } }Hello, world!
編譯后:
class Home extends Component { render() { return React.createElement("div", { onClick: () => console.log("hello") }, React.createElement("h1", null, "Hello, world!"), React.createElement(Blog, { title: "deepred" })); } }
在開發(fā)中,有了JSX后我們基本不怎么需要用到createElement方法,但如果我們需要實現(xiàn)這樣一個組件:
// 根據(jù)傳入的type屬性,渲染成相應(yīng)的html元素console.log("hello")}>this is a h1 this is a p
我們不太可能根據(jù)type的屬性,一個個if else去判斷對應(yīng)的標簽:
function Tag(props) { const { type, ...other } = props; if (type === "h1") { return{props.children}
} if (type === "p") { return{props.children}
} }
這時,就需要用到底層的api了:
function Tag(props) { const { type, ...other } = props; return React.createElement(type, other, props.children); }自己實現(xiàn)一個JSX渲染器
虛擬dom本質(zhì)就是一個js對象:
const vnode = { tag: "div", attrs: { className: "container" }, children: [ { tag: "img", attrs: { src: "1.png" }, children: [] }, { tag: "h3", attrs: {}, children: ["hello"] } ] }
可以通過在每個文件的上方添加/** @jsx h */來告訴@babel/preset-react用h方法名代替JSX(默認方法是React.createElement)
/** @jsx h */ const element =Hello
;
/** @jsx h */ const element = h("h1", { id: "container", className: "home" }, "Hello");
現(xiàn)在讓我們開始創(chuàng)建自己的h函數(shù)吧!
function h(nodeName, attributes, ...args) { // 使用concat是為了扁平化args,因為args數(shù)組里面的元素可能也是數(shù)組 // h("div", {}, [1, 2, 3]) h("d", {}, 1, 2, 3) 都是合法的調(diào)用 const children = args.length ? [].concat(...args) : null; return { nodeName, attributes, children }; }
const vnode = h("div", { id: "urusai" }, "Hello!"); // 返回 // { // "nodeName": "div", // "attributes": { // "id": "urusai" // }, // "children": [ // "Hello!" // ] // }
h的作用就是返回一個vnode,有了vnode,我們還需要把vnode轉(zhuǎn)成真實的dom:
function render(vnode) { if (typeof vnode === "string") { // 生成文本節(jié)點 return document.createTextNode(vnode); } // 生成元素節(jié)點并設(shè)置屬性 const node = document.createElement(vnode.nodeName); const attributes = vnode.attributes || {}; Object.keys(attributes).forEach(key => node.setAttribute(key, attributes[key])); if (vnode.children) { // 遞歸調(diào)用render生成子節(jié)點 vnode.children.forEach(child => node.appendChild(render(child))); } return node; }
現(xiàn)在讓我們使用這兩個方法吧:
/** @jsx h */ const vnode =Hello!; const node = render(vnode); document.body.appendChild(node);
編譯轉(zhuǎn)碼后:
/** @jsx h */ const vnode = h("div", { id: "urusai" }, "Hello!"); const node = render(vnode); document.body.appendChild(node);
我們還可以遍歷數(shù)組:
/** @jsx h */ const items = ["baga", "hentai", "urusai"]; const vnode =
編譯轉(zhuǎn)碼后:
/** @jsx h */ const items = ["baga", "hentai", "urusai"]; const vnode = h("ul", null, items.map((item, index) => h("li", { key: index }, item))); const list = render(vnode); document.body.appendChild(list);
通過h render兩個函數(shù),我們就實現(xiàn)了一個很簡單的JSX渲染器!!!
參考WTF is JSX
JSX In Depth
React Without JSX
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/102716.html
摘要:然而之前的相當于從最頂層的組件開始,自頂向下遞歸調(diào)用,不會被中斷,這樣就會持續(xù)占用瀏覽器主線程。眾所周知,是單線程運行,長時間占用主線程會阻塞其他類似于樣式計算布局繪制等運算,從而出現(xiàn)掉幀的情況。 前言 首先歡迎大家關(guān)注我的Github博客,也算是對我的一點鼓勵,畢竟寫東西沒法獲得變現(xiàn),能堅持下去也是靠的是自己的熱情和大家的鼓勵,希望大家多多關(guān)注呀!從今年年初離開React開發(fā)崗,...
摘要:本系列文章重拾主要參考王福朋知多少,結(jié)合自己的理解和學(xué)習(xí)需要,修改或添加了一些內(nèi)容,難免有失偏頗,僅供自我學(xué)習(xí)參考之用。 工作中或多或少的寫一些css,但總感覺掌握的不夠扎實,時而需要查閱一下知識點。我想,一方面跟缺少科班出身式的系統(tǒng)學(xué)習(xí)有關(guān),另一方面也苦于一直未尋覓到一套合我胃口教程。直到我讀到了王福朋css知多少系列文章,使我有了重新系統(tǒng)學(xué)習(xí)css的想法。 本系列文章(重拾css)...
摘要:也就是說我們操作的幾何公式中的未知變量,而具體的畫圖操作則由渲染引擎處理,而不是我們苦苦哀求設(shè)計師幫忙。 前言 ?當CSS3推出border-radius屬性時我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)border-top-left/right-radius的水平半徑之和大于元素寬度時,實際值會按比...
摘要:本系列將稍微深入探討一下那個貌似沒什么好玩的魔法堂重拾之解構(gòu)魔法堂重拾之圖片作邊框魔法堂重拾之不僅僅是圓角魔法堂重拾之更廣闊的遐想解構(gòu)說起我們自然會想起,而由條緊緊包裹著的邊組成,所以的最小操作單元是。 前言 ?當CSS3推出border-radius屬性時我們是那么欣喜若狂啊,一想到終于不用再添加額外元素來模擬圓角了,但發(fā)現(xiàn)border-radius還分水平半徑和垂直半徑,然后又發(fā)現(xiàn)...
摘要:前端日報精選一行代碼的逆向工程譯只需四個步驟使用實現(xiàn)頁面過渡動畫如何實現(xiàn)一個基于的模板引擎解剖組件的多種寫法與演進深入理解筆記擴展對象的功能性中文基礎(chǔ)系列一之實現(xiàn)抽獎刮刮卡橡皮擦掘金小游戲個人文章和最常用的特征眾成翻譯常用語法總 2017-08-08 前端日報 精選 一行 JavaScript 代碼的逆向工程【譯】只需四個步驟:使用 React 實現(xiàn)頁面過渡動畫如何實現(xiàn)一個基于 DOM...
閱讀 703·2021-11-18 10:02
閱讀 3579·2021-09-02 10:21
閱讀 1725·2021-08-27 16:16
閱讀 2058·2019-08-30 15:56
閱讀 2386·2019-08-29 16:53
閱讀 1373·2019-08-29 11:18
閱讀 2953·2019-08-26 10:33
閱讀 2642·2019-08-23 18:34