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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

React中级学习(第二天)

發(fā)布時(shí)間:2023/12/13 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 React中级学习(第二天) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

JSX 語法的轉(zhuǎn)化過程 (了解)

演示 : babel中文網(wǎng)試一試 let h1 =

  • JSX 僅僅是createElement() 方法的語法糖 (簡(jiǎn)化語法)
  • JSX 語法 被 @babel/preset-react 插件編譯為 createElement() 方法
  • React 元素:是一個(gè)對(duì)象,用來描述你希望在屏幕上看到的內(nèi)容
  • React 元素 最后 被 ReactDOM.render(<Child/>,document.getElementById('root')) 渲染顯示到頁面

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-9hqEG5rw-1596329786917)(C:/Users/wangyu123/Desktop/新建文件夾/面試題/md-imgs/jsx.png)]

  • 演示:
render () {const el = <h1 className='greeting'>Hello JSX</h1>console.log(el);return el }react更新機(jī)制 簡(jiǎn)化 : 虛擬DOM 然后呢?? 1. jsx => 虛擬DOM => 真實(shí)的DOM 2. jsx數(shù)據(jù)發(fā)生變化 => 新的虛擬DOM 3. 新的虛擬DOM 和 舊的虛擬DOM對(duì)比 => 通過Diff算法找到有差異的地方 => 更新1步驟的真實(shí)的DOM

組件更新機(jī)制

  • setState 的兩個(gè)作用
    • 修改state
    • 重新調(diào)用render , 更新組件(UI)
  • 過程 : 父組件重新渲染時(shí), 也會(huì)重新染當(dāng)前組件子樹

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-l4SpZboe-1596329786920)(C:/Users/wangyu123/Desktop/新建文件夾/面試題/md-imgs/更新機(jī)制.png)]

演示代碼 :

  • App > P1+P2> C1+C2
//2. 類組件 class App extends React.Component {state = {}render() {return (<div style={{ background:'pink', display:'flex' }}><P1></P1><P2></P2></div>)} } class P1 extends React.Component {render() {return (<div style={{ background:'red',flex:1 }}><p>P1</p></div>)} } class P2 extends React.Component {state = {name :'zs'}render() {return (<div style={{ background: 'skyblue',flex:1 }}><p onClick={this.handle}>P2- { this.state.name }</p><C1></C1><C2></C2></div>)}handle = () => { this.setState({name : 'ls'})} } class C1 extends React.Component {render () {console.log('child1 更新了');return (<div style={{background:'yellow' }}><p>child1</p></div>)} } class C2 extends React.Component {render () {console.log('child2 更新了');return (<div style={{background:'lime' }}><p>child2</p></div>)} }
  • 這樣效果是出來了,但是它確實(shí)有很嚴(yán)重的性能問題, 因?yàn)樽咏M件都沒有任何變化,如果重新渲染,那么就會(huì)重新調(diào)用render() 渲染頁面, 有損性能
  • 所以需要進(jìn)行處理 組件性能優(yōu)化

組件性能優(yōu)化

優(yōu)化1: 減輕 state

  • 原則 : state 中 只存儲(chǔ)跟組件渲染相關(guān)的數(shù)據(jù) (比如 : count / 列表數(shù)據(jù) 等)
  • 不用做渲染的數(shù)據(jù) 不要放在 state 中, (比如 定時(shí)器 id )
// 定時(shí)器的 timerId 就 不需要放到state 中,, 只是用來清除 定時(shí)器, 和渲染無關(guān)componentDidMount() {// timerId存儲(chǔ)到this中,而不是state中this.timerId = setInterval(() => {}, 2000)}componentWillUnmount() {clearInterval(this.timerId) }

優(yōu)化2 : 避免不必要的重新渲染

  • 組件更新機(jī)制 : 父組件更新會(huì)引起子組件也被更新
  • 問題 : 子組件沒有任何變化時(shí), 也會(huì)重新渲染
  • 如何避免不必要的重新渲染呢 ?
  • 解決方式 : 使用 鉤子函數(shù)` shouldComponentUpdate(nextProps, nextState)
    • nextProps : 最新的屬性
    • nextState : 最新的狀態(tài)
    • 場(chǎng)景 : 比較更新前后的 state 或者 props 是否相同, 來決定是否 更新組件
  • 作用 : 通過返回值 決定該組件是否需要重新渲染, 返回true ,表示重新渲染, false 表示不重新渲染
  • 觸發(fā)時(shí)機(jī) : 更新階段的鉤子函數(shù), 組件重新渲染 執(zhí)行
    • 順序 : shouldComponentUpdate() ==> render() ==> componentDidMount()
  • 演示 : 點(diǎn)擊父組件的計(jì)算器的數(shù)據(jù)count
// 演示1 : 子組件里 通過 shouldComponentUpdate() { return true or false } - true-更新- false-不更新// 演示2 : 獲取 父?jìng)鬟^來的屬性, 奇數(shù)更新,偶數(shù)不更新, shouldComponentUpdate(nextProps,nextState)- nextProps : 最新的屬性- nextState : 最新的狀態(tài)- if(nextState.count % 2 == 0) {return false }else { return true}// 演示3 : 就一個(gè)組件里有number 值, 點(diǎn)擊產(chǎn)生隨機(jī)值, 比較前后生成的隨機(jī)值是否一致,不一致就更細(xì), 一致就不需要更新 // count : Math.floor(Math.random()*3)shouldComponentUpdate(nextProps,nextState) {// 上一個(gè)的值 最新的值console.log(this.state.count === nextState.count)// 本次的 nextState.number// 上一次的 this.state.number// 或者 通過 if..else..判斷 return this.state.count !== nextState.count}

優(yōu)化3 : 純組件 - PureComponent

  • 純組件
  • 作用 : 自動(dòng)實(shí)現(xiàn)了 shouldComponentUpdate() 鉤子函數(shù), 不需要再手動(dòng)對(duì)比更新前后的props 或者 state , 來阻止不必要的更新了
  • 原理 : PureComponent 內(nèi)部, 會(huì)別對(duì)比更新前后的props 以及更新前后的state , 只要有一個(gè)不同, 就會(huì)讓組件更新, 只有在兩者都相同的情況下, 才會(huì)阻止組件更新
class Hello extends React.PureComponent {} // 把那個(gè)方法 shouldComponentUpdate() 刪除掉, 已經(jīng) PureComponent已經(jīng)封裝好了

PureComponent 內(nèi)部原理

參考 : API Reference => React => React.PureComponent

  • PureComponent

  • 說明 : PureComponent 內(nèi)部會(huì)比較更新前后的 props 和 state 分別進(jìn)行淺對(duì)比

  • 對(duì)于簡(jiǎn)單/值類型來說, 比較兩個(gè)值是否相同 (直接賦值即可, 沒有坑)

// 將 React.Component 替換為: React.PureComponent class Hello extends React.PureComponent {state = {// number 就是一個(gè)普通的值類型的數(shù)據(jù)number: 0}handleClick = () => {const newNumber = Math.floor(Math.random() * 3)console.log(newNum);// 對(duì)于 值類型 來說,沒有任何坑,直接使用即可// 更新前的 number:0// 更新后的 number:2// PureComponent 內(nèi)部會(huì)進(jìn)行如下對(duì)比:// 更新前的number === 更新后的number// 如果這兩個(gè)值相同,內(nèi)部,相當(dāng)于在 shouldComponentUpdate 鉤子函數(shù)中返回 false ,阻止組件更新。// 如果這兩個(gè)值不同,內(nèi)部,相當(dāng)于在 shouldComponentUpdate 鉤子函數(shù)中返回 true ,更新組件。this.setState({number: newNumber})}render() {return (<div><h1>隨機(jī)數(shù):{this.state.number}</h1><button onClick={this.handleClick}>隨機(jī)生成</button></div>)} }
  • 對(duì)于引用類型來說, 只比較對(duì)象的引用(地址) 是否相同
    • 造成的結(jié)果 : 對(duì)象里 的數(shù)據(jù)變化,不更新
const { obj } = this.statelet newNum = Math.floor(Math.random() * 3) console.log(newNum);// 雖然value 值 也可以從 react-dev-tools 里調(diào)試 value值確實(shí)都變了,但是 obj 一直沒有變 obj.value = newNumthis.setState({obj })
  • 正確做法 : 根據(jù)現(xiàn)有狀態(tài)生成一個(gè)新對(duì)象, 然后再更新狀態(tài)
const newObj = {...this.state.obj} // 創(chuàng)建一個(gè)新對(duì)象 newObj.value = Math.floor(Math.random() * 3) this.setState({obj: newObj })
  • 正確做法說明:
    • 在 PureComponent 中 使用引用類型 的狀態(tài)時(shí), 應(yīng)該每次都創(chuàng)建一個(gè)新的狀態(tài), 而不是直接修改當(dāng)前狀態(tài)
    • 因?yàn)镻ureComponent 是淺對(duì)比, 所以,如果直接修改當(dāng)前對(duì)象中的屬性, 會(huì)造成: 對(duì)象中的值變了, 但是引用地址沒有改變, 而導(dǎo)致組件不會(huì)被更新, 這樣的話就出現(xiàn)bug了
  • 注意 , 在 React 中, ( 不管是PureComponent 還是 Component ) , 都不要直接修改引用類型的狀態(tài)值, 而是要?jiǎng)?chuàng)建一個(gè)新的狀態(tài), 修改新的狀態(tài),然后再更新

在 React 組件 中更新應(yīng)用類型的狀態(tài)

  • 文檔 : 不可變數(shù)據(jù)的力量
  • 注意 : 對(duì)于引用類型的狀態(tài)來說, 應(yīng)該創(chuàng)建新的狀態(tài), 而不要直接修改當(dāng)前狀態(tài)
  • 原則 : 狀態(tài)不可變!!! 數(shù)據(jù)不要變, 直接創(chuàng)建新的
  • 對(duì)象狀態(tài) :
// 對(duì)象 state = {obj : {value : 123} }//ES5 // 新加 之前的值 修改內(nèi)容 const newObj = Object.assign( {}, this.state.obj, {value : '新的值'} ) this.setState({obj:newObj }) // es6 this.setState({obj : {...this.state.obj, value: '新的值'} })
  • 數(shù)組狀態(tài)
// 數(shù)組: state = {list: ['a', 'b'] }// ES5: this.setState({list: this.state.list.concat([ 'c' ]) // ['a', 'b', 'c'] })// ES6: this.setState({list: [...this.state.list, 'c'] })// 刪除數(shù)組元素:[].filter()

虛擬DOM的真正價(jià)值

  • 虛擬 DOM 的真正價(jià)值從來都不是性能。
  • 真正的價(jià)值:虛擬DOM 能夠讓 React 擺脫瀏覽器的限制(束縛)。也就是,只要能夠運(yùn)行JS代碼的地方,就能夠運(yùn)行 React。
  • 跨平臺(tái)
    • JSX => 虛擬DOM => react-dom => DOM 元素=> 瀏覽器
    • JSX => 虛擬DOM => React-Native => ios和安卓的元素 => 移動(dòng)混合開發(fā)
    • JSX => 虛擬DOM => 工具 => VR

React 組件

  • (state, props) => UI

路由基礎(chǔ)

路由介紹

  • 路由 : 就是一套映射規(guī)則, 是url中 哈希值 與 展示視圖 之間的一種對(duì)應(yīng)關(guān)系
  • 為什么要學(xué)習(xí)路由 ?
    • 現(xiàn)代的前端應(yīng)用大多都是 SPA(單頁應(yīng)用程序),也就是只有一個(gè) HTML 頁面的應(yīng)用程序。
    • 因?yàn)樗挠脩趔w驗(yàn)更好、對(duì)服務(wù)器的壓力更小,所以更受歡迎。
    • 為了有效的使用單個(gè)頁面來管理原來多頁面的功能,前端路由 應(yīng)運(yùn)而生。
  • 使用React路由簡(jiǎn)單來說,就是配置 路徑組件(配對(duì))
spa缺點(diǎn)1. 學(xué)習(xí)成本大 學(xué)習(xí)路由2. 不利于SEO

基本使用

  • 安裝 : yarn add react-router-dom
// 1 導(dǎo)入路由中的三個(gè)組件 import { BrowerRouter , Link, Route } from 'react-router-dom'const Hello = () => {// 2 使用 BrowerRouter 組件包裹整個(gè)應(yīng)用(才能使用路由)return (<BrowerRouter><div><h1>React路由的基本使用:</h1>{/* 3 使用 Link 組件,創(chuàng)建一個(gè)導(dǎo)航菜單(路由入口) */}<Link to="/first">頁面一</Link>{/* 4 使用 Route 組件,配置路由規(guī)則以及要展示的組件(路由出口) */}<Route path="/first" component={First} /></div></BrowerRouter>) }

常用組件的使用介紹

  • 引入的三個(gè)組件
// HashRouter => 哈希模式 => 帶 # => 修改的是 location.hash import { HashRouter , Link, Route } from 'react-router-dom' //帶# // BrowserRouter => history模式 => 不帶 # => 修改的是 location.pathname import { BrowserRouter , Link, Route } from 'react-router-dom' //不帶#
  • BrowserRouter 組件 : 使用 Router 組件包裹整個(gè)應(yīng)用 (才能使用路由)
  • Link 組件 : 創(chuàng)建一個(gè)導(dǎo)航菜單 (路由入口)
    • 最終會(huì)生成一個(gè)a標(biāo)簽, 通過 to 屬性指定 pathname(history /) 或 hash(哈希模式 #)
  • Route 組件 : 用來配置路由規(guī)則和要展示的組件 (路由出口)
    • path : 配置路由規(guī)則
    • component : 指定當(dāng)前路由 規(guī)則匹配時(shí)要展示的組件
    • Route 組件放在哪, 組件內(nèi)容就展示在哪, 并且每一個(gè)路由都是一個(gè)單獨(dú)的Route組件

路由的執(zhí)行過程

  • 當(dāng)點(diǎn)擊 Link 的時(shí)候,就會(huì)修改瀏覽器中的 pathname
  • 只要 瀏覽器地址欄中的 pathname 發(fā)生改變,React 路由就會(huì)監(jiān)聽到這個(gè)改變
  • React 路由監(jiān)聽到 pathname 改變后,就會(huì)遍歷所有 Route 組件,分別使用 Route 組件中的 path 路由規(guī)則,與當(dāng)前的 瀏覽器地址欄中的pathname進(jìn)行匹配
  • 只要匹配成功,就會(huì)把當(dāng)前 Route 對(duì)應(yīng)的組件,展示在頁面中
  • 注意:匹配時(shí),不是找到第一個(gè)匹配的路由就停下來了。而是: 所有的 Route 都會(huì)進(jìn)行匹配,只要匹配就會(huì)展示該組件。
    • 也就是說:在一個(gè)頁面中,可以有多個(gè) Route 同時(shí)被匹配

使用 Switch 組件 ,匹配一個(gè)

{/* Switch 只會(huì)讓 組件顯示出來一個(gè) */} <Switch><Route path="/one" component={One}></Route><Route path="/two" component={Three}></Route><Route path="/two" component={Two}></Route> </Switch>

編程式導(dǎo)航

  • 改變?nèi)肟诘娜N方式 :

  • 手動(dòng)輸入

  • 聲明式導(dǎo)航 : (html)

    • 編程式導(dǎo)航 : 通過js代碼來實(shí)現(xiàn)的跳轉(zhuǎn)/返回 (js)
  • 編程式導(dǎo)航 :

  • 可以通過props 拿到 跳轉(zhuǎn)和返回的方法

  • 正常的組件, 打印 props => 默認(rèn)是 一個(gè)空對(duì)象 {}

  • 凡是參與路由匹配出來的組件 , 路由都會(huì)給他們傳入三個(gè)屬性 history, location, match

  • history : (主要用來編程式導(dǎo)航)

    • push() 跳轉(zhuǎn)到另外一個(gè)頁面 push(path,state)
    • goBack() 返回上一個(gè)頁面
    • replace() 跳轉(zhuǎn)到另外一個(gè)頁面
  • location : (位置路徑的)

  • pathname : 路徑

    • state : 通過跳轉(zhuǎn)傳遞的數(shù)據(jù)
  • match : 獲取參數(shù)

    • params : 可以拿到動(dòng)態(tài)路由里的參數(shù) params : {id : 123}
* - push() 跳轉(zhuǎn)到另外一個(gè)頁面* - goBack() 返回上一個(gè)頁面* - replace() 跳轉(zhuǎn)到另外一個(gè)頁面** - push 和 replace 區(qū)別* - push() 跳轉(zhuǎn) - 記錄訪問的歷史 (可逆)* - replace() 跳轉(zhuǎn) - 不記錄訪問的歷史 (不可逆)* One : <button onClick={this.jump}>跳轉(zhuǎn)到two</button> 演示* Two : <button onClick={this.back}>返回到One</button> 返回

HashRouter 傳參的方式和 BrowserRouter 傳參的方式不一樣this.props.history.push({pathname: '/pay',state: {name: 'zs'}})

默認(rèn)路由 - 根路徑 /

  • 默認(rèn)路由地址為:/
  • 默認(rèn)路由在進(jìn)入頁面的時(shí)候,就會(huì)自動(dòng)匹配
{/* / 表示默認(rèn)路由規(guī)則 */} <Route path="/" component={Home} />

匹配模式

問題:當(dāng) Link組件的 to 屬性值為 “/login”時(shí),為什么 默認(rèn)路由/ 也被匹配成功?

  • 默認(rèn)情況下,React 路由是: 模糊匹配模式
  • 模糊匹配:只要 pathname 以 path 開頭就會(huì)匹配成功
    • path 代表Route組件的path屬性
    • pathname 代表Link組件的to屬性(也就是url中 location.pathname)
  • 精確匹配:只有當(dāng) path 和 pathname 完全匹配時(shí)才會(huì)展示該路由
  • 解決辦法 : 給 Route 組件添加 exact 屬性,讓其變?yōu)榫_匹配模式
// 添加 exact 之后, 此時(shí),該組件只能匹配 pathname=“/” 這一種情況 <Route exact path="/" component=... />// 再演示 : /one/two/three

重定向

  • 需求 : 使用 重定向 '/' => '/one'
  • 方式1 : render-props
<Route exact path='/'render={ () => {return <Redirect to='/one' />} }></Route>
  • 方式2 - children
<Route exact path='/'><Redirect to='/one' /> </Route>

路由兩種模式的說明

哈希模式

1. 訪問路徑 : http://localhost:8080/#/one http://localhost:8080/#/two2. 服務(wù)器接收到的 (服務(wù)器是不會(huì) 接收 # 后面的內(nèi)容的)3. 不管訪問的路徑是什么樣的 http://localhost:8080 ==> 服務(wù)器返回的默認(rèn) 的就是 index.html4. 后面的 /one 和 /two 由路由來使用, 根據(jù)路由匹配規(guī)則找到對(duì)應(yīng)的組件顯示 5. 哈希模式 不管是 開發(fā)階段還是發(fā)布階段,都是沒有問題的

history 模式

1. 訪問路徑 : http://localhost:8080/one http://localhost:8080/two2. 服務(wù)器接收到的 http://localhost:8080/one 和 http://localhost:8080/two但是,/one 和 /two 這個(gè)路徑是不需要服務(wù)器端做任何處理的。 3. http://localhost:8080/getNewshttp://localhost:8080/detail 它們都是 接口地址 , 后面遇到 類似 /one 和 /two 都會(huì)以為是接口 是要返回?cái)?shù)據(jù)的呢? 3. 所以,應(yīng)該在服務(wù)器端添加一個(gè)路由配置,直接返回 SPA 的 index.html 頁面就行啦。 4. 類似處理app.get('/getNews', (req,res) => {// 根據(jù) res 返回 對(duì)應(yīng)的數(shù)據(jù)res.json { ..... }})app.get('/detail', (req,res) => {// 根據(jù) res 返回 對(duì)應(yīng)的數(shù)據(jù)res.json { ..... }})// 最后 額外再多加一個(gè), 專門用來返回 index.htmlapp.use('*', (req,res) => {res.sendFile('index.html')})

總結(jié) :

history模式 : - 開發(fā)階段 : webpack腳手架已經(jīng)處理好了, - 發(fā)布階段 : 服務(wù)器是公司的服務(wù)器, 可能就會(huì)報(bào)錯(cuò) - 我們要做的就是`告訴后臺(tái)`,我們使用的 是 history模式,讓他專門處理一下,就可以了 - 如果后臺(tái)不給處理,或者處理不好, 我們就使用 `哈希模式`

類似 /one 和 /two 都會(huì)以為是接口 是要返回?cái)?shù)據(jù)的呢?
3. 所以,應(yīng)該在服務(wù)器端添加一個(gè)路由配置,直接返回 SPA 的 index.html 頁面就行啦。
4. 類似處理
app.get(’/getNews’, (req,res) => {
// 根據(jù) res 返回 對(duì)應(yīng)的數(shù)據(jù)
res.json { … }
})
app.get(’/detail’, (req,res) => {
// 根據(jù) res 返回 對(duì)應(yīng)的數(shù)據(jù)
res.json { … }
})

// 最后 額外再多加一個(gè), 專門用來返回 index.html app.use('*', (req,res) => {res.sendFile('index.html') }) #### 總結(jié) : ```js history模式 : - 開發(fā)階段 : webpack腳手架已經(jīng)處理好了, - 發(fā)布階段 : 服務(wù)器是公司的服務(wù)器, 可能就會(huì)報(bào)錯(cuò) - 我們要做的就是`告訴后臺(tái)`,我們使用的 是 history模式,讓他專門處理一下,就可以了 - 如果后臺(tái)不給處理,或者處理不好, 我們就使用 `哈希模式`

總結(jié)

以上是生活随笔為你收集整理的React中级学习(第二天)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

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