日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

React简介、虚拟DOM、Diff算法、创建React项目、JSX语法、组件、组件声明方式、组件传值props和state、组件的生命周期

發(fā)布時(shí)間:2025/3/15 javascript 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React简介、虚拟DOM、Diff算法、创建React项目、JSX语法、组件、组件声明方式、组件传值props和state、组件的生命周期 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

React簡(jiǎn)介:

前面只是簡(jiǎn)單介紹移動(dòng)APP開(kāi)發(fā),后面還會(huì)繼續(xù)深入介紹移動(dòng)app開(kāi)發(fā);其中想要用ReactNative開(kāi)發(fā)出更出色的應(yīng)用,那么就得學(xué)好React,下面將介紹React:

React 是一個(gè)由 Facebook 開(kāi)發(fā)用于構(gòu)建用戶界面的漸進(jìn)式 JavaScript 庫(kù),其特點(diǎn):聲明式設(shè)計(jì)、高效、靈活、JSX、組件化、單向數(shù)據(jù)流。

React也是組件化的,與vue不同的是:React直接使用JS代碼編寫(xiě)組件(結(jié)構(gòu)、樣式、邏輯混合在js代碼中)。

React是前端三大框架中誕生最早的框架,社區(qū)龐大,技術(shù)團(tuán)隊(duì)實(shí)力雄厚。

虛擬DOM:

操作原生DOM是一件非常耗性能的事,操作虛擬DOM就不會(huì)那么耗性能了,操作虛擬DOM時(shí)采用Different算法,只更新變化的虛擬DOM部分;虛擬DOM指通過(guò)程序員手動(dòng)模擬出來(lái)類(lèi)似原生DOM的對(duì)象,如下面模擬一個(gè)帶有鏈接的p元素:

var p = {//定義一個(gè)對(duì)象tagName:'p',//標(biāo)簽名為:pattrs:{//定義屬性:class:'font16'},children:[//定義內(nèi)容,相當(dāng)于innerText'跳轉(zhuǎn)到:',{//在父標(biāo)簽的children中再定義以對(duì)象,其方法和定義p一樣:tagName:'a',//標(biāo)簽名為:aattrs:{//屬性:href:'https://www.baidu.com',},children:[//定義內(nèi)容:'百度']}]}

Diff算法:

Diff算法用于對(duì)比新舊虛擬DOM的算法,其中有三部分:tree diff、component diff、element diff,其區(qū)別:

tree diff :新舊DOM樹(shù)逐層對(duì)比的方式,對(duì)比所有層節(jié)點(diǎn)來(lái)找到被更新的節(jié)點(diǎn)后修改舊DOM。

component diff:組件之間的對(duì)比,當(dāng)對(duì)比組件的時(shí)候,如果兩個(gè)組件的類(lèi)型相同,則這個(gè)組件暫時(shí)不需要被更新,如果組件的類(lèi)型不同,則立即移除舊組件,新建一個(gè)組件,替換到被移除的位置。

element diff:組件中每個(gè)元素之間的對(duì)比。

使用虛擬DOM創(chuàng)建React項(xiàng)目(導(dǎo)入資源型):

使用React開(kāi)發(fā)項(xiàng)目時(shí),必須安裝兩個(gè)包:react、react-dom;react是用來(lái)創(chuàng)建組件、組件生命周期等。react-dom用來(lái)操作DOM。創(chuàng)建react項(xiàng)目步驟:

//1.新建一個(gè)項(xiàng)目文件夾,并在文件夾打開(kāi)終端鍵入:npm init -y 初始化一個(gè)package.json文件//2.終端輸入:cnpm install react react-dom --save 安裝react和react-dom到運(yùn)行里,ReactNative開(kāi)發(fā)中不建議使用cnpm裝包//3.新建src文件夾并新建main.js文件并引入:react和react-dom:開(kāi)始編寫(xiě)react中js主文件(并新建index.html文件,文件中留渲染的div)import React from 'react';import ReactDOM from 'react-dom';//4.在main.js文件中使用React提供的API操作元素://4-1使用React.createElement()創(chuàng)建一個(gè)虛擬DOM,接收至少三個(gè)參數(shù):參數(shù)1:字符串(標(biāo)簽類(lèi)型),參數(shù)2:對(duì)象(標(biāo)簽屬性),參數(shù)3開(kāi)始:當(dāng)前元素子節(jié)點(diǎn),可放多個(gè)虛擬dom,如:var mydiv = React.createElement('div',{class:'mydiv',id:'box'},'這是一個(gè)div元素');//<div class='mydiv' id='box'>這是一個(gè)div元素</div>var spanp = React.createElement('span',{class:'spans'},'被span標(biāo)簽包裹的文本');//<span class='spans'>被span標(biāo)簽包裹的文本</span>var textp = React.createElement('p',{class:'tp'},'p標(biāo)簽文本中',spanp);//<p class='tp'>p標(biāo)簽文本中<span class='spans'>被span標(biāo)簽包裹的文本</span></p>// 4-2使用ReactDOM.render()將虛擬DOM渲染到頁(yè)面中,參數(shù)1:渲染DOM內(nèi)容,參數(shù)2:渲染的dom元素位置(獲取DOM的方式),如:ReactDOM.render(mydiv,document.getElementById('app'));//這里app表示index.htlm文件中一個(gè)id值為app的標(biāo)簽,如<div id='app'></div>//4.webpack打包構(gòu)建后,在dist目錄下的文件是正??梢栽L問(wèn)的。

JSX:

不難發(fā)現(xiàn)使用js創(chuàng)建元素的方式是非常繁瑣的,因此這里介紹一款可以解決這個(gè)問(wèn)題語(yǔ)法:JSX;

HTML 語(yǔ)言直接寫(xiě)在 JavaScript 語(yǔ)言中,不加任何引號(hào),這就是 JSX 語(yǔ)法,它允許 HTML 與 JavaScript 的混寫(xiě);

它是 一種 JavaScript 的語(yǔ)法擴(kuò)展, 我們推薦在 React 中使用 JSX 來(lái)描述用戶界面,JSX 是在 JavaScript 內(nèi)部實(shí)現(xiàn)的;元素是構(gòu)成 React 應(yīng)用的最小單位,JSX 就是用來(lái)聲明 React 當(dāng)中的元素(底層實(shí)際就是通過(guò)上面js創(chuàng)建元素的)使用JSX語(yǔ)法時(shí)首先要安裝:(cnpm install babel-preset-react -D)并配置在.babelrc文件中,babel-preset-react 用來(lái)轉(zhuǎn)換JSX代碼。(注意新版本:babel-preset-react-app,此環(huán)境應(yīng)該基于上面環(huán)境)

與瀏覽器的 DOM 元素不同,React 當(dāng)中的元素事實(shí)上是普通的對(duì)象,如:

// 注意:想要正常運(yùn)行JSX語(yǔ)法:還需要以下兩步://1.在項(xiàng)目目錄下新建:.babelic文件,其配置代碼如下:{"presets": ["env", "stage-0", "react"],"plugins": ["transform-runtime"]}//2.cnpm i babel-preset-env babel-preset-stage-0 babel-plugin-transform-runtime --save ,下載上面配置依賴的包。//3.配置完以上環(huán)境后,應(yīng)該使用webpack打包后才可以以files的方式打正常訪問(wèn)react項(xiàng)目import React from 'react';import ReactDOM from 'react-dom';var titles = '這是一個(gè)提示';var elements =<div>{/* JSX語(yǔ)法中允許有一個(gè)根節(jié)點(diǎn),根節(jié)點(diǎn)中可以嵌套其它元素 */}<p title={titles}>hello</p>{/*JSX中使用變量用{}包裹,實(shí)際指使用js語(yǔ)法時(shí)用{}包裹*/}<a href="#">hello</a><p className='textp'>hello</p>{/*在JSX中使用className代替class屬性,因?yàn)閏lass在js中只一個(gè)關(guān)鍵字*/}<label htmlFor="">hello</label>{/* 在JSX中for使用htmlFor代替 */}</div>const box = document.getElementById('box');ReactDOM.render(elements,box);//總結(jié)://1.當(dāng)編譯時(shí)遇到尖括號(hào)<>當(dāng)JSX執(zhí)行,當(dāng)遇到大括號(hào){}當(dāng)js執(zhí)行//2.JSX語(yǔ)法中使用className代替class屬性//3.在JSX中for使用htmlFor代替//4.jsx語(yǔ)法中只能使用一個(gè)根元素//5.jsx中數(shù)組會(huì)自動(dòng)展開(kāi)

JSX 中注釋:

寫(xiě)法一:

{// 注釋// ...}

寫(xiě)法二(單行推薦):

{/* 單行注釋 */}

寫(xiě)法三(多行推薦):

{/** 多行注釋*/}

JSX 不同寫(xiě)法:

Babel 會(huì)把 JSX 通過(guò)React.createElement() 函數(shù)編譯,每個(gè) React 元素都是一個(gè)真實(shí)的 JavaScript 對(duì)象;下面幾種方式是等價(jià)的,如:

const element = (<h1 className="greeting">Hello, world!</h1>);const element = React.createElement('h1',{className: 'greeting'},'Hello, world!');const element = {type: 'h1',props: {className: 'greeting',children: 'Hello, world'}};const element = {tagName:'h1',attrs:{className: 'greeting'},children:['Hello, world']}

組件:

React 允許將代碼封裝成組件,然后像插入普通 HTML 標(biāo)簽一樣,在網(wǎng)頁(yè)中插入這個(gè)組件即可使用;組件規(guī)則注意事項(xiàng):組件名的第一個(gè)首字母必須大寫(xiě),class聲明式組件必須有 render 方法,組件內(nèi)必須有且只有一個(gè)根節(jié)點(diǎn),組件的屬性可以在組件內(nèi)通過(guò)props 獲取(函數(shù)需要傳遞參數(shù):props;類(lèi)直接通過(guò): this.props),如:

函數(shù)式聲明組件(無(wú)狀態(tài)):

名字不能用小寫(xiě),React 在解析的時(shí)候,是以標(biāo)簽的首字母來(lái)區(qū)分的,如果首字母是小寫(xiě)則當(dāng)作 HTML 來(lái)解析,如果首字母是大寫(xiě)則當(dāng)作組件來(lái)解析。

// 函數(shù)名大寫(xiě),組件名為函數(shù)名// 函數(shù)式聲明組件,必須有return關(guān)鍵字,即使沒(méi)內(nèi)容也應(yīng)該:return nullfunction Header(props){return (//當(dāng)返回多行代碼時(shí),建議使用小括號(hào)括起來(lái)<div><p>這是header組件{props.name}</p>{/* 這里直接通過(guò){屬性名}的方式是不能拿到屬性值的,需要給函數(shù)傳遞一個(gè)參數(shù)如:props等,在通過(guò)這個(gè)參數(shù)點(diǎn)出屬性:{props.name},且這些屬性只讀 */}</div>)}const box = document.getElementById('box');// 通過(guò) <函數(shù)名/> 的方式定義組件名;組件中傳遞參數(shù)使用屬性的方式,如:name={變量名},age={變量名};分開(kāi)傳遞參數(shù)很不方便,可以使用es6中屬性擴(kuò)散語(yǔ)法傳遞一個(gè)對(duì)象達(dá)到同樣效果:var obj = {name:'jack',age:'28',gender:'男'}var cont = <div><Header {...obj}/> {/* es6中屬性擴(kuò)散語(yǔ)法 */}</div>ReactDOM.render(cont,box);

抽離組件:

上面組件聲明在同一個(gè)js文件中,沒(méi)有達(dá)到減少主文件代碼量的問(wèn)題,想要減少主文件代碼量,就得將組件抽離出來(lái),如:

// 被抽離的組件header.js文件:(擴(kuò)展:組件可以使用jsx后綴名,但是需要在webpack.config.js文件中配置解析jsx文件的loader:loader和js一樣,可連寫(xiě)為:( js|jsx)$ 、jsx?$ )import React from 'react';//導(dǎo)入React,注意:React首字母必須大寫(xiě)function Header(props){return (<div><p>這是header組件{props.name}</p></div>)}// 抽離組件需要暴露出:export default Header;//或直接在函數(shù)或類(lèi)前面加 export default;// 在主文件(main.js)中使用這個(gè)組件:// 導(dǎo)入組件:import Header from './components/header.js';// 在主文件中使用 <Header><Header/> (簡(jiǎn)寫(xiě):<Header/>)使用組件即可

類(lèi)方式聲明組件(有狀態(tài)):

// 通過(guò)class定義一個(gè)Header組件,extends 繼承了React中Componentclass Header extends React.Component { render() { //使用render函數(shù),函數(shù)中返回組件類(lèi)容:return (<div><p>這是header組件{this.props.names}</p>{/*class聲明的組件拿傳遞的值通過(guò):this.props點(diǎn)屬性名,也是只可讀的*/}</div>)}}; ReactDOM.render(<Header names='jack'/>, document.getElementById('box'));// 抽離組件的方式和函數(shù)聲明組件的方式中一樣

組件傳值props和state:

state 和 props區(qū)別在于props 是不可變的,而 state 可以改變。函數(shù)式組件只能通過(guò) props 來(lái)傳遞數(shù)據(jù),不能通過(guò)state傳值;class定義的組件都可以使用它們傳值。

class Header extends React.Component { constructor(props){//class定義的類(lèi)中如果實(shí)現(xiàn)了繼承,默認(rèn)就有constructor函數(shù),只是看不見(jiàn);當(dāng)寫(xiě)出這個(gè)構(gòu)造函數(shù)時(shí),要通過(guò)super調(diào)用:super(props);//表示父類(lèi)的構(gòu)造函數(shù)console.log(props);//在constructor中是不能直接使用props的,想要使用,就得在constructor中傳遞props// constructor中的this.state表示私有數(shù)據(jù)對(duì)象,類(lèi)似vue中data(){},this.state中定義的數(shù)據(jù)是可改變的,通過(guò)this.state點(diǎn)屬性拿到,如:this.state={messages:'hello',names:'jack'}}render() { return (<div><p>這是header組件{this.props}</p><p>這是header組件{this.state.messages}</p><button onClick={this.change}>變更messages的值</button>{/* jsx中使用事件時(shí),必須使用駝峰命名法,且處理函數(shù)名前面加this. */}</div>)}//React函數(shù)中this默認(rèn)指向undefined,若想this指向class類(lèi),可以使用箭頭函數(shù):如:// change(){// this.state.messages = '修改hello為word';// }change=()=>{//這里是將箭頭函數(shù)賦值給change,箭頭函數(shù)中this依舊指向class類(lèi)// this.state.messages = '修改hello為word';//通過(guò)this.state方式修改數(shù)據(jù)只是單向的,內(nèi)存中數(shù)據(jù)是修改了,但是頁(yè)面沒(méi)有自動(dòng)刷新,因此也不推薦,推薦setState()方法異步修改,如// this.setState({//setState()方法中傳遞一個(gè)對(duì)象,對(duì)象中傳入要修改的屬性,如:// messages:'word',// names:'lucky'// })// this.setState(function(prevState,props){//setState也支持傳遞一個(gè)函數(shù),但是函數(shù)必須return一個(gè)對(duì)象;函數(shù)中第一個(gè)參數(shù)表示修改數(shù)據(jù)之前的數(shù)據(jù),第二個(gè)參數(shù)是外界傳遞過(guò)來(lái)的數(shù)據(jù)屬性// return {// messages:'word'// }// })this.setState(function(prevState,props){//setState()因?yàn)閟etState是異步修改數(shù)據(jù)的,想要確保拿到最新的數(shù)據(jù),那么,可以給setState繼續(xù)傳遞一個(gè)參數(shù)為:回調(diào)函數(shù),在回調(diào)函數(shù)里面拿到的數(shù)據(jù)是比較保險(xiǎn)的,如:return {messages:'word'}},function(){console.log(this.state.messages);})}}; ReactDOM.render(<Header/>, document.getElementById('box'));// 抽離組件的方式和函數(shù)聲明組件的方式中一樣

組件的生命周期:

組件從創(chuàng)建到運(yùn)行再到銷(xiāo)毀,這期間伴隨著各種各樣的事件,這些事件統(tǒng)稱(chēng)為組件的生命周期函數(shù);

組件生命周期分為三部分:組件創(chuàng)建階段(命周期函數(shù)一生只創(chuàng)建一次)、組件運(yùn)行階段(生命周期函數(shù)根據(jù)props和state的狀態(tài)是否改變運(yùn)行0-N次)、組件銷(xiāo)毀階段(生命周期函數(shù)一生只執(zhí)行一次)。

import React from 'react';import ReactDOM from 'react-dom';import ReactTypes from 'prop-types';//導(dǎo)入數(shù)據(jù)校驗(yàn)?zāi)Kclass Header extends React.Component { constructor(props){super(props);//1.使用:this.state={}初始化組件私有狀態(tài),初始化組件私有數(shù)據(jù)this.state={messages:'hello',numstate:props.num//因?yàn)閜rops中的值時(shí)只讀的,想要修改值,就得使用state存值,但是state存的值是固定的,因此這里可以傳遞一個(gè)動(dòng)態(tài)的值,即props的值,此時(shí)頁(yè)面的值應(yīng)該為對(duì)應(yīng)的state值。}}//2.使用:static defaultProps = {}定義默認(rèn)的值供程序正常運(yùn)行,如:static defaultProps = {num:0}//3.使用:static propTypes = {}做數(shù)據(jù)校驗(yàn),防止傳過(guò)來(lái)的數(shù)據(jù)無(wú)效,如:static propTypes = {//特別注意:做校驗(yàn)需要安裝一個(gè)包prop-types: npm install prop-types ,并在開(kāi)頭導(dǎo)入num:ReactTypes.number//如果需要檢驗(yàn)其他數(shù)據(jù)類(lèi)型,可閱讀prop-types原文;當(dāng)做完數(shù)據(jù)校驗(yàn)時(shí),在組件中傳遞過(guò)來(lái)的值類(lèi)型不符合時(shí)會(huì)報(bào)警告}// 4.使用:componentWillMount(){}組件即將被掛載到頁(yè)面時(shí)觸發(fā)函數(shù),虛擬DOM也沒(méi)創(chuàng)建(不能被拿到),因此此頁(yè)面不能操作頁(yè)面,可以操作數(shù)據(jù),如:componentWillMount(){console.log(this.state.messages);//數(shù)據(jù)可被拿到console.log(this.props.num);//數(shù)據(jù)可被拿到this.myFunction();//函數(shù)可被調(diào)用console.log(document.getElementById('testp'));//不能被獲取}// 5.使用:render(){}即將渲染內(nèi)存中的虛擬DOM,該函數(shù)執(zhí)行完后內(nèi)存中已經(jīng)渲染好數(shù)據(jù)了,但是還沒(méi)有被掛載到頁(yè)面上,如:render() { //render中不能使用this.setState方法,否則會(huì)進(jìn)入死循環(huán)return (<div>{/* <p id='testp'>num的值:{this.props.num}</p> */}<p id='testp' onClick={this.addnumstate}>num的值自增為:{this.state.numstate}</p>{/*修改為可改變的state值*/}<span ref='spans'>hello</span>{/* 利用refs屬性可以快速獲取到該節(jié)點(diǎn) */}</div>)}// 6.使用:componentDidMount(){}頁(yè)面已經(jīng)有可見(jiàn)的DOM元素了,此時(shí)可以拿到render中的DOM,如:componentDidMount(){console.log(document.getElementById('testp'));//可以獲取DOM元素,可對(duì)其進(jìn)行操作(原生DOM型,但是需要注意this指向問(wèn)題,可使用箭頭函數(shù),但是不推薦原生方式),如:// document.getElementById('testp').οnclick=()=>{// this.setState({// numstate:this.state.numstate++// })// }//推薦React中事件綁定的方式,如testp標(biāo)簽中}//7.使用:conmponentWillReceiveProps(){}當(dāng)子組件的屬性props改變時(shí)觸發(fā)此方法,但是第一次渲染時(shí)不會(huì)被觸發(fā),如:conmponentWillReceiveProps(nextProps){//這里的數(shù)據(jù)是舊的,但是通過(guò)第一個(gè)參數(shù)nextProps.屬性名,拿到的是最新的數(shù)據(jù)console.log('當(dāng)外界傳遞過(guò)來(lái)新的props時(shí),才會(huì)觸發(fā)該事件執(zhí)行');console.log(next.Props.num);}addnumstate=()=>{//使用箭頭函數(shù)改變this指向?yàn)轭?lèi)的實(shí)例;注意:在dom中掉用次函數(shù)時(shí)在函數(shù)名前加thisthis.setState({numstate:this.state.numstate++})}myFunction(){console.log('測(cè)試componentWillMount是否可以調(diào)用外部函數(shù)');}// 以上是組件創(chuàng)建階段生命周期,下面將介紹組件運(yùn)行階段生命周期:// 1.使用:shouldComponentUpdate(){}里面return一個(gè)布爾值,判斷是否要更新頁(yè)面上數(shù)據(jù),當(dāng)為true時(shí)可以改變頁(yè)面上數(shù)據(jù),當(dāng)為false時(shí)不能改變頁(yè)面上的數(shù)據(jù);無(wú)論是true或false,內(nèi)存中數(shù)據(jù)都是改變重新渲染了shouldComponentUpdate(nextProps,nextState){//此方法中可傳入兩個(gè)參數(shù):第一個(gè)表示最新的props,第二個(gè)表示最新的stateconsole.log(nextState.numstate);return true;//這里應(yīng)該使用傳入?yún)?shù)做出邏輯后return 布爾值}// 2.當(dāng)shouldComponentUpdate中返回false時(shí),會(huì)重新返回到shouldComponentUpdate執(zhí)行,若果返回的是true,則執(zhí)行下面的:componentWillUpdate(){}將要更新數(shù)據(jù),此時(shí)頁(yè)面和內(nèi)存中數(shù)據(jù)都未被更新,如:componentWillUpdate(){//此時(shí)頁(yè)面上數(shù)據(jù)都是舊的console.log(this.refs.spans.innerHTML);//使用refs獲取ref設(shè)置的值}// 3.這里有一個(gè)運(yùn)行時(shí)的render方法,但是里面數(shù)據(jù)h還是舊的。// 4.使用:componentDidUpdate(){}更新了頁(yè)面和內(nèi)存中的數(shù)據(jù),此時(shí)數(shù)據(jù)都是最新的,如:componentDidUpdate(){//此時(shí)頁(yè)面上數(shù)據(jù)都是新的console.log(this.refs.spans.innerHTML);}}; ReactDOM.render(<Header num='校驗(yàn)時(shí)傳入無(wú)效數(shù)據(jù)時(shí),會(huì)報(bào)警告'/>, document.getElementById('box'));

對(duì)上面組件生命周期流程總結(jié)如下圖:

提示:本文圖片等素材來(lái)源于網(wǎng)絡(luò),若有侵權(quán),請(qǐng)發(fā)郵件至郵箱:810665436@qq.com聯(lián)系筆者刪除。
筆者:苦海

總結(jié)

以上是生活随笔為你收集整理的React简介、虚拟DOM、Diff算法、创建React项目、JSX语法、组件、组件声明方式、组件传值props和state、组件的生命周期的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。