JavaScript中React 面向組件編程(下)
前言:
在React面向組件編程中,除了上一章節(jié)的組件實例的三大核心屬性以外,還有很多重要的內(nèi)容比如:React 的生命周期,受控組件與非受控組件,高階函數(shù)和函數(shù)柯里化的理解等,在本文中會給大家繼續(xù)講解React 面向組件編程中剩余的內(nèi)容。
一、受控組件與非受控組件
表單的組件分類:
- 受控組件
- 非受控組件
多數(shù)情況下,推薦使用受控組件實現(xiàn)表單。在受控組件中,表單數(shù)據(jù)由組件控制。
另外一種是非受控組件,這種方式下表單組件由DOM自身控制。
1. 受控組件
- 受控組件通過
props
獲取其當前值,并通過回調(diào)函數(shù)(比如onChange
)通知變化 - 表單狀態(tài)發(fā)生變化時,都會通知
React
,將狀態(tài)交給React
進行處理,比如可以使用useState
存儲 - 受控組件中,組件渲染出的狀態(tài)與它的
value
或checked
屬性相對應 - 受控組件會更新
state
的流程
class Login extends React.Component { // 初始化狀態(tài) state = { username:'', // 用戶名 password:'', // 密碼 } // 保存用戶名到狀態(tài)中 saveUsername=(event)=>{ this.setState({username:event.target.value}) } // 保存密碼到狀態(tài)中 savePassword=(event)=>{ this.setState({password:event.target.value}) } // 表單提交的回調(diào) handleSubmit=(event)=>{ event.preventDefault(); // 阻止默認事件 let {username,password} = this.state alert(`你輸入的用戶名是${username},密碼是${password}`) } render(){ return( <div> <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}> 用戶名:<input type="text" onChange={this.saveUsername} name="username" /> 密碼:<input type="text" onChange={this.savePassword} name="password" /> <button type="submit">登錄</button> </form> </div> ) } }
2. 非受控組件
非受控組件將數(shù)據(jù)存儲在 DOM
中,而不是組件內(nèi),這比較類似于傳統(tǒng)的 HTML
表單元素。
- 非受控組件的值不受組件自身的
state
和props
控制 - 非受控組件使用
ref
從DOM
中獲取元素數(shù)據(jù)
class Login extends React.Component { handleSubmit=(event)=>{ // console.log(e>=event) event.preventDefault(); // 阻止默認事件 let {username,password} = this alert(`你輸入的用戶名是${username.value},密碼是${password.value}`) } render(){ return( <div> <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}> 用戶名:<input type="text" ref={c=>this.username = c} name="username" /> 密碼:<input type="text" ref={c=>this.password = c} name="password" /> <button type="submit">登錄</button> </form> </div> ) } }
3. 效果展示
4. 總結(jié):
React
中的組件分為受控組件和非受控組件- 受控組件的兩個要點:
- 組件的
value
屬性與React
中的狀態(tài)綁定 - 組件內(nèi)聲明了
onChange
事件處理value
的變化
- 組件的
- 非受控組件更像是傳統(tǒng)的
HTML
表單元素,數(shù)據(jù)存儲在DOM
中,而不是組件內(nèi)部,獲取數(shù)據(jù)的方式是通過ref
引用 - 一些建議:
- 盡可能使用受控組件
- 受控組件是將狀態(tài)交由
React
處理,可以是任何元素,不局限于表單元素 - 對于有大量表單元素的頁面,使用受控組件會使程序變得繁瑣難控,此時使用非受控組件更為明智
- 在受控組件中,數(shù)據(jù)流是單向的(
state
是變化來源),因此在改變state
時都應該使用setState
,而不要強制賦值 Refs
不能用于函數(shù)式組件,因為函數(shù)式組件沒有實例- 在函數(shù)式組件內(nèi)部,是可以使用
Refs
的
二、組件的生命周期
所謂的React生命周期,就是指組件從被創(chuàng)建出來,到被使用,最后被銷毀的這么一個過程;
而在這個過程中,React提供了我們會自動執(zhí)行的不同的鉤子函數(shù),我們稱之為生命周期函數(shù);
組件的生命周期大致分為三個階段:組件掛載階段,組件更新階段,組件銷毀卸載階段
react在版本16.3前后存在兩套生命周期,16.3之前為舊版,之后則是新版,雖有新舊之分,但主體上大同小異。
1. 對生命周期的理解
- 組件從創(chuàng)建到死亡它會經(jīng)歷一些特定的階段。
- React組件中包含一系列勾子函數(shù)(生命周期回調(diào)函數(shù)), 會在特定的時刻調(diào)用。
- 我們在定義組件時,會在特定的生命周期回調(diào)函數(shù)中,做特定的工作。
2. 生命周期的三個階段(舊)
- 初始化階段: 由ReactDOM.render()觸發(fā)—初次渲染
- constructor()
- componentWillMount()
- render()
- componentDidMount()
- 更新階段: 由組件內(nèi)部this.setSate()或父組件重新render觸發(fā)
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
- 卸載組件: 由ReactDOM.unmountComponentAtNode()觸發(fā)
- componentWillUnmount()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生命周期舊</title> </head> <body> <!-- 準備好一個容器 --> <div id="test"></div> <!-- 引入 React 核心庫 --> <script src="../js/react.development.js"></script> <!-- 引入 react-dom 用于支持 react 操作 DOM --> <script src="../js/react-dom.development.js"></script> <!-- 引入babel: 1. ES6 ==> ES5 2. jsx ==> js --> <script src="../js/babel.min.js"></script> <script type="text/babel"> class Count extends React.Component { state = { count:0 } add = ()=>{ // 獲取原狀態(tài) let {count} = this.state // 更新狀態(tài) this.setState({count:count+1}) } death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) } force = ()=>{ this.forceUpdate() // 強制更新 } // 數(shù)據(jù)更新的 ‘閥門~' shouldComponentUpdate() { console.log("Count --- shouldComponentUpdate"); return true // 這里必須有返回4值,其次返回值默認是true } // 組件將要更新的鉤子 componentWillUpdate() { console.log("Count ---- componentWillUpdate"); } // 組件更新完成的鉤子 componentDidUpdate() { console.log("Count ---- componentDidUpdate"); } render(){ console.log("render"); let {count} = this.state return( <div> <h2>當前求和為:{count}</h2> <button onClick={this.add}>點我+1</button> <button onClick={this.death}>卸載組件</button> <button onClick={this.force}>不更改任何狀態(tài)中的數(shù)據(jù),強制更新</button> </div> ) } } // 父組件 class A extends React.Component { state = {carName:'小三輪'} changeCar = ()=>{ this.setState({carName:"賓利"}) } render(){ console.log('A ---- render'); return( <div> <div>我是A組件</div> <button onClick={this.changeCar}>換車</button> <B carName={this.state.carName}></B> </div> ) } } // 子組件 class B extends A { // 組件將要接收新的props的鉤子 componentWillReceiveProps(){ console.log('B ---- componentWillReceiveProps'); } // 數(shù)據(jù)更新的 ‘閥門~' shouldComponentUpdate() { console.log("B --- shouldComponentUpdate"); return true // 這里必須有返回4值,其次返回值默認是true } // 組件將要更新的鉤子 componentWillUpdate() { console.log("B ---- componentWillUpdate"); } // 組件更新完成的鉤子 componentDidUpdate() { console.log("B ---- componentDidUpdate"); } render(){ console.log('B ---- render'); return( <div> 我是B組件,接收到的車是:{this.props.carName} </div> ) } } ReactDOM.render(<A />,document.getElementById('test')) </script> </body> </html>
3. 生命周期的三個階段(新)
- 初始化階段: 由ReactDOM.render()觸發(fā)—初次渲染
- constructor()
- getDerivedStateFromProps
- render()
- componentDidMount()
- 更新階段: 由組件內(nèi)部this.setSate()或父組件重新render觸發(fā)
- getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
- 卸載組件: 由ReactDOM.unmountComponentAtNode()觸發(fā)
- componentWillUnmount()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>生命周期新</title> </head> <body> <!-- 準備好一個容器 --> <div id="test"></div> <!-- 引入 React 核心庫 --> <script src="../js/17.0.1/react.development.js"></script> <!-- 引入 react-dom 用于支持 react 操作 DOM --> <script src="../js/17.0.1/react-dom.development.js"></script> <!-- 引入babel:1. ES6 ==> ES52. jsx ==> js --> <script src="../js/17.0.1/babel.min.js"></script> <script type="text/babel"> class Count extends React.Component { state = { count:0 } add = ()=>{ // 獲取原狀態(tài) let {count} = this.state // 更新狀態(tài) this.setState({count:count+1}) } death = ()=>{ ReactDOM.unmountComponentAtNode(document.getElementById('test')) } force = ()=>{ this.forceUpdate() // 強制更新 } // 數(shù)據(jù)更新的 ‘閥門~' shouldComponentUpdate() { console.log("Count --- shouldComponentUpdate"); return true // 這里必須有返回4值,其次返回值默認是true } // 組件將要更新的鉤子 componentWillUpdate() { console.log("Count ---- componentWillUpdate"); } // 組件更新完成的鉤子 componentDidUpdate() { console.log("Count ---- componentDidUpdate"); } render(){ console.log("render"); let {count} = this.state return( <div> <h2>當前求和為:{count}</h2> <button onClick={this.add}>點我+1</button> <button onClick={this.death}>卸載組件</button> <button onClick={this.force}>不更改任何狀態(tài)中的數(shù)據(jù),強制更新</button> </div> ) } } // 父組件 class A extends React.Component { state = {carName:'小三輪'} constructor(props) { state } changeCar = ()=>{ this.setState({carName:"賓利"}) } static getDerivedStateFromProps(props, state) { // 這里必須要一個返回值 ==> state or null // 這里的state會覆蓋掉原本的狀態(tài),并且后續(xù)也無法修改 // 能將外部的接收的props 賦值給組件自身的 state // 如果你希望自身的state一直,全部依賴于外部的props,那么可以使用這個生命周期函數(shù) return {carName:"QQ"} } // 獲取護具更新前的快照,能拿到舊的props和state // 必須有返回值 getSnapshotBeforeUpdate = (prevProps, prevState) => { } render(){ console.log('A ---- render'); return( <div> <div>我是A組件</div> <button onClick={this.changeCar}>換車</button> <B carName={this.state.carName}></B> </div> ) } } // 子組件 class B extends A { // 組件將要接收新的props的鉤子 UNSAFE_componentWillReceiveProps(){ console.log('B ---- componentWillReceiveProps'); } // 數(shù)據(jù)更新的 ‘閥門~' shouldComponentUpdate() { console.log("B --- shouldComponentUpdate"); return true // 這里必須有返回4值,其次返回值默認是true } // 將要掛載時 UNSAFE_componentWillMount() { console.log("Count --- componentWillUnMount"); } // 組件將要更新的鉤子 UNSAFE_componentWillUpdate() { console.log("B ---- componentWillUpdate"); } // 組件更新完成的鉤子 componentDidUpdate() { console.log("B ---- componentDidUpdate"); } render(){ console.log('B ---- render'); return( <div> 我是B組件,接收到的車是:{this.props.carName} </div> ) } } ReactDOM.render(<A />,document.getElementById('test')) </script> </body> </html>
4. 新舊生命周期的區(qū)別
- 新生命周期中去掉了三個
will
鉤子,分別為componentWillMount
、componentWillReceiveProps
、componentWillUpdate
; - 新生命周期中新增了兩個鉤子,分別為
getDerivedStateFromProps
(從props
中得到衍生的state
)和getSnapshotBeforeUpdate
。
5. 重要的勾子
render
:初始化渲染或更新渲染調(diào)用componentDidMount
:開啟監(jiān)聽, 發(fā)送ajax請求componentWillUnmount
:做一些收尾工作, 如: 清理定時器
6. 即將廢棄的勾子
componentWillMount
componentWillReceiveProps
componentWillUpdate
警告:
現(xiàn)在使用會出現(xiàn)警告,下一個大版本需要加上
UNSAFE_
前綴才能使用,以后可能會被徹底廢棄,不建議使用。
三、高階函數(shù)和函數(shù)柯里化的理解
1. 高階函數(shù)
如果一個函數(shù)符合下面2個規(guī)范中的任何一個,那么它就屬于一個高階函數(shù)
- 若A函數(shù),接收的參數(shù)是一個函數(shù),那么A就可以稱為高階函數(shù)
- 若A函數(shù),它的返回值依然是一個函數(shù),那么A就可以稱為高階函數(shù)
常見的高階函數(shù):Promise,setTimeout,arr.map(數(shù)組方法)
2. 函數(shù)的柯里化
通過函數(shù)繼續(xù)調(diào)用,返回值為函數(shù)的方式,實現(xiàn)多次接受參數(shù),最后統(tǒng)一處理的函數(shù)編碼形式
function sum(a){ return (b)=>{ return (c)=>{ return a + b + c } } } const result = sum(1)(2)(3) console.log(result);
3. 使用函數(shù)柯里化代碼示例
class Login extends React.Component { // 初始化狀態(tài) state = { username:'', // 用戶名 password:'', // 密碼 } // 保存表單數(shù)據(jù)到狀態(tài)中 saveFormDate=(dataType,event)=>{ // 標識當前標簽 this.setState({[dataType]:event.target.value}) } // 表單提交的回調(diào) handleSubmit=(event)=>{ event.preventDefault(); // 阻止默認事件 let {username,password} = this.state alert(`你輸入的用戶名是${username},密碼是${password}`) } render(){ return( <div> <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}> 用戶名:<input type="text" onChange={(event)=>this.saveFormDate('username',event)} name="username" /> 密碼:<input type="text" onChange={(event)=>this.saveFormDate('password',event)} name="password" /> <button type="submit">登錄</button> </form> </div> ) } }
4. 不用函數(shù)柯里化代碼示例
class Login extends React.Component { // 初始化狀態(tài) state = { username:'', // 用戶名 password:'', // 密碼 } // 保存表單數(shù)據(jù)到狀態(tài)中 saveFormDate=(dataType)=>{ // 標識當前標簽 return (event)=>{ // 這里的回調(diào)誰執(zhí)行? input標簽的 onChange事件 this.setState({[dataType]:event.target.value}) } } // 表單提交的回調(diào) handleSubmit=(event)=>{ event.preventDefault(); // 阻止默認事件 let {username,password} = this.state alert(`你輸入的用戶名是${username},密碼是${password}`) } render(){ return( <div> <form action="https://www.baidu.com/" onSubmit={this.handleSubmit}> 用戶名:<input type="text" onChange={this.saveFormDate('username')} name="username" /> 密碼:<input type="text" onChange={this.saveFormDate('password')} name="password" /> <button type="submit">登錄</button> </form> </div> ) } }
總結(jié):
以上就是 React 面向組件編程(下),不懂得也可以在評論區(qū)里問我或私聊我詢問。
以上就是JavaScript中React 面向組件編程(下)的詳細內(nèi)容,更多關(guān)于React 面向組件編程的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
axios請求響應數(shù)據(jù)加解密封裝實現(xiàn)詳解
這篇文章主要為大家介紹了axios請求響應數(shù)據(jù)加解密封裝實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03React組件中監(jiān)聽函數(shù)獲取不到最新的state問題
這篇文章主要介紹了React組件中監(jiān)聽函數(shù)獲取不到最新的state問題問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01react中的useImperativeHandle()和forwardRef()用法
這篇文章主要介紹了react中的useImperativeHandle()和forwardRef()用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08react-native 圓弧拖動進度條實現(xiàn)的示例代碼
本篇文章主要介紹了react-native 圓弧拖動進度條實現(xiàn)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04