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. 即將廢棄的勾子
componentWillMountcomponentWillReceivePropscomponentWillUpdate
警告:
現(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-03
React組件中監(jiān)聽函數(shù)獲取不到最新的state問題
這篇文章主要介紹了React組件中監(jiān)聽函數(shù)獲取不到最新的state問題問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-01-01
react中的useImperativeHandle()和forwardRef()用法
這篇文章主要介紹了react中的useImperativeHandle()和forwardRef()用法,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
react-native 圓弧拖動進度條實現(xiàn)的示例代碼
本篇文章主要介紹了react-native 圓弧拖動進度條實現(xiàn)的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04

