文章目錄
- 一、defaultProps 和 prop-types
- 使用 defaultProps 設置組件的默認值
- 使用prop-types進行props數據類型的校驗
- 代碼舉例
- 二、事件綁定
- 原生js做事件綁定
- 使用 React 提供的方法,做事件綁定
- 三、生命周期函數:shouldComponentUpdate()
- 四、在js代碼中獲取html標簽的屬性
- 五、生命周期函數:componentWillReceiveProps()
一、defaultProps 和 prop-types
使用 defaultProps 設置組件的默認值
React 中,使用靜態的 defaultProps
屬性,來設置組件的默認屬性值。
格式舉例:
// 在 React 中,使用靜態的 defaultProps 屬性,來設置組件的默認屬性值static defaultProps = {initcount: 0 // 如果外界沒有傳遞 initcount,那么,自己初始化一個數值(比如0)};
使用prop-types進行props數據類型的校驗
在組件中,可以通過 prop-types
把外界傳遞過來的屬性,做類型校驗。如果類型不匹配,控制臺會彈出告警。
注意:如果要為 傳遞過來的屬性做類型校驗,必須安裝 React 提供的 第三方包,叫做 prop-types
。
格式舉例:
static propTypes = {initcount: ReactTypes.number // 使用 prop-types 包,來定義 initcount 為 number 類型};
下方代碼中,在引用組件的時候,如果類型不匹配:
// 使用 render 函數渲染 虛擬DOM
ReactDOM.render(<div>{/* 規定,每個用戶在使用 組件的時候,必須傳遞一個 默認的 數值,作為 組件初始化的 數據 */}<Counter initcount="我是string類型"></Counter></div>,document.getElementById("app")
);
代碼舉例
我們把 defaultProps
和 prop-types
來舉個例子。
(1)index.html:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head><body><!-- 容器,通過 React 渲染得到的 虛擬DOM,會呈現到這個位置 --><div id="app"></div>
</body></html>
(2)main.js:
// JS打包入口文件
// 1. 導入包
import React from "react";
import ReactDOM from "react-dom";// 導入計數器組件
import Counter from "./components/Counter.jsx";// 使用 render 函數渲染 虛擬DOM
ReactDOM.render(<div>{/* 規定,每個用戶在使用 組件的時候,必須傳遞一個 默認的 數值,作為 組件初始化的 數據 */}<Counter initcount={0}></Counter></div>,document.getElementById("app")
);
(3)/components/Counter.jsx:
import React from "react";
// 注意: prop-types 包中職能跟單一,只提供了 一些常見的 數據類型,用于做類型校驗
import ReactTypes from "prop-types";export default class Counter extends React.Component {constructor(props) {super(props);// 初始化組件,保存的是組件的私有數據this.state = {msg: "ok",count: props.initcount // 把 父組件傳遞過來的 initcount 賦值給子組件 state 中的 count值。這樣的話,就把 count 值改成了可讀可寫的 state 屬性。因此,以后就能實現“點擊 按鈕 ,count 值 + 1”的需求了};}// 在 React 中,使用靜態的 defaultProps 屬性,來設置組件的默認屬性值static defaultProps = {initcount: 0 // 如果外界沒有傳遞 initcount,那么,自己初始化一個 數值,為0};render() {return (<div><div><h3>這是 Counter 計數器組件 </h3><p>當前的計數是:{this.state.count}</p></div></div>);// 當 return 執行完畢后, 虛擬DOM創建好了,但是,還沒有掛載到真正的頁面中}
}
二、事件綁定
案例:點擊按鈕后,計數器 +1。
原生js做事件綁定
代碼舉例:
(1)index.html:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head><body><!-- 容器,通過 React 渲染得到的 虛擬DOM,會呈現到這個位置 --><div id="app"></div>
</body></html>
(2)main.js:
// JS打包入口文件
// 1. 導入包
import React from "react";
import ReactDOM from "react-dom";// 導入計數器組件
import Counter from "./components/Counter.jsx";// 使用 render 函數渲染 虛擬DOM
ReactDOM.render(<div>{/* 規定,每個用戶在使用 組件的時候,必須傳遞一個 默認的 數值,作為 組件初始化的 數據 */}<Counter initcount={0}></Counter></div>,document.getElementById("app")
);
(3)/components/Counter.jsx:
import React from "react";
// 注意: prop-types 包的職能跟單一,只提供了 一些常見的 數據類型,用于做類型校驗
import ReactTypes from "prop-types";export default class Counter extends React.Component {constructor(props) {super(props);// 初始化組件,保存的是組件的私有數據this.state = {msg: "ok",count: props.initcount // 把 父組件傳遞過來的 initcount 賦值給子組件 state 中的 count值。這樣的話,就把 count 值改成了可讀可寫的 state 屬性。因此,以后就能實現“點擊 按鈕 ,count 值 + 1”的需求了};}// 在 React 中,使用靜態的 defaultProps 屬性,來設置組件的默認屬性值static defaultProps = {initcount: 0 // 如果外界沒有傳遞 initcount,那么,自己初始化一個數值(比如0)};// 這是創建一個 靜態的 propTypes 對象,在這個對象中,可以把 外界傳遞過來的屬性,做類型校驗static propTypes = {initcount: ReactTypes.number // 使用 prop-types 包,來定義 initcount 為 number 類型};render() {return (<div><div><h3>這是 Counter 計數器組件 </h3><input type="button" value="+1" id="btn" /><p>當前的計數是:{this.state.count}</p></div></div>);// 當 return 執行完畢后, 虛擬DOM創建好了,但是,還沒有掛載到真正的頁面中}// 當組件掛載到頁面上之后,會進入這個生命周期函數,只要進入這個生命周期函數了,必然說明,頁面上,已經有可見的DOM元素了componentDidMount() {// 在這個函數中,我們可以放心的去 操作 頁面上你需要使用的 DOM 元素了。// 也就是說,如果我們想操作DOM元素,最早,只能在 componentDidMount 中進行。document.getElementById("btn").onclick = () => {this.setState({count: this.state.count + 1});};}
}
使用 React 提供的方法,做事件綁定
代碼舉例:
(1)index.html和 (2)main.js 的代碼不變,和上一小段中的代碼一致。
(3)/components/Counter.jsx:
import React from "react";
// 注意: prop-types 包的職能跟單一,只提供了 一些常見的 數據類型,用于做類型校驗
import ReactTypes from "prop-types";export default class Counter extends React.Component {constructor(props) {super(props);// 初始化組件,保存的是組件的私有數據this.state = {msg: "ok",count: props.initcount // 把 父組件傳遞過來的 initcount 賦值給子組件 state 中的 count值。這樣的話,就把 count 值改成了可讀可寫的 state 屬性。因此,以后就能實現“點擊 按鈕 ,count 值 + 1”的需求了};}// 在 React 中,使用靜態的 defaultProps 屬性,來設置組件的默認屬性值static defaultProps = {initcount: 0 // 如果外界沒有傳遞 initcount,那么,自己初始化一個數值(比如0)};// 這是創建一個 靜態的 propTypes 對象,在這個對象中,可以把 外界傳遞過來的屬性,做類型校驗static propTypes = {initcount: ReactTypes.number // 使用 prop-types 包,來定義 initcount 為 number 類型};render() {return (<div><div><h3>這是 Counter 計數器組件 </h3>{/* 這里的 this 指向的是 Counter 組件的實例 */}<input type="button" value="+1" id="btn" onClick={this.myMethod} /><p>當前的計數是:{this.state.count}</p></div></div>);// 當 return 執行完畢后, 虛擬DOM創建好了,但是,還沒有掛載到真正的頁面中}// 點擊事件的方法定義myMethod = () => {// 修改組件的state里面的值this.setState({count: this.state.count + 1});};
}
三、生命周期函數:shouldComponentUpdate()
在 shouldComponentUpdate() 函數中,必須要求返回一個布爾值。
需要注意的是:如果返回的值是 false,則不會繼續執行后續的生命周期函數,而是直接退回到了 運行中 的狀態。因為此時,后續的 render 函數并沒有被調用,因此頁面不會被更新,但是組件的 state 狀態,卻被修改了。這種情況,我們也可以這樣理解:如果返回值為 false,此時只是更新了 state 里面的數值,但是并沒有渲染到 DOM節點上。
利用上面這個特性,我們可以來舉個例子。
舉例:實現 Counter 計數器只在偶數情況下更新。
實現思路:在 shouldComponentUpdate() 函數中,如果 state 中 的count 的值為奇數,就 return false;否則就 return true。
代碼實現:(我們在上面的Counter.jsx
代碼基礎之上,做添加)
// 判斷組件是否需要更新shouldComponentUpdate(nextProps, nextState) {// 經過打印測試發現:在 shouldComponentUpdate 中,通過 this.state.count 拿到的值,是上一次的舊數據,并不是當前最新的;// 解決辦法:通過 shouldComponentUpdate 函數的第二個參數 nextState,可以拿到 最新的 state 數據。console.log(this.state.count + " ---- " + nextState.count);// 需求: 如果 state 中的 count 值是偶數,則 更新頁面;如果 count 值 是奇數,則不更新頁面。最終實現的的頁面效果:2,4,6,8,10,12....// return this.state.count % 2 === 0 ? true : falsereturn nextState.count % 2 === 0 ? true : false;}
上面這部分的代碼,和 render() 方法是并列的。我們需要注意里面的注釋,關注 nextState 參數的用法。
四、在js代碼中獲取html標簽的屬性
比如說,如果想獲取 html標簽的 innerHTML 屬性,做法如下:
通過原生 js 獲取:
document.getElementById('myh3').innerHTML
也可以通過 React 提供的 refs
獲取:
this.refs.h3.innerHTML
代碼舉例:
(3)/components/Counter.jsx:
import React from "react";
// 注意: prop-types 包的職能跟單一,只提供了 一些常見的 數據類型,用于做類型校驗
import ReactTypes from "prop-types";export default class Counter extends React.Component {constructor(props) {super(props);// 初始化組件,保存的是組件的私有數據this.state = {msg: "ok",count: props.initcount // 把 父組件傳遞過來的 initcount 賦值給子組件 state 中的 count值。這樣的話,就把 count 值改成了可讀可寫的 state 屬性。因此,以后就能實現“點擊 按鈕 ,count 值 + 1”的需求了};}// 在 React 中,使用靜態的 defaultProps 屬性,來設置組件的默認屬性值static defaultProps = {initcount: 0 // 如果外界沒有傳遞 initcount,那么,自己初始化一個數值(比如0)};// 這是創建一個 靜態的 propTypes 對象,在這個對象中,可以把 外界傳遞過來的屬性,做類型校驗static propTypes = {initcount: ReactTypes.number // 使用 prop-types 包,來定義 initcount 為 number 類型};render() {return (<div><div><h3>這是 Counter 計數器組件 </h3>{/* 這里的 this 指向的是 Counter 組件的實例 */}<input type="button" value="+1" id="btn" onClick={this.myMethod} /><h3 id="myh3" ref="mymyh3">當前的計數是:{this.state.count}</h3></div></div>);// 當 return 執行完畢后, 虛擬DOM創建好了,但是,還沒有掛載到真正的頁面中}// 點擊事件的方法定義myMethod = () => {// 修改組件的state里面的值this.setState({count: this.state.count + 1});};// 判斷組件是否需要更新shouldComponentUpdate(nextProps, nextState) {// 需求: 如果 state 中的 count 值是偶數,則 更新頁面;如果 count 值 是奇數,則不更新頁面。最終實現的的頁面效果:2,4,6,8,10,12....// 經過打印測試發現:在 shouldComponentUpdate 中,通過 this.state.count 拿到的值,是上一次的舊數據,并不是當前最新的;// 解決辦法:通過 shouldComponentUpdate 函數的第二個參數 nextState,可以拿到 最新的 state 數據。console.log(this.state.count + " ---- " + nextState.count);// return this.state.count % 2 === 0 ? true : false// return nextState.count % 2 === 0 ? true : false;return true;}// 組件將要更新。此時尚未更新,在進入這個 生命周期函數的時候,內存中的虛擬DOM是舊的,頁面上的 DOM 元素 也是舊的componentWillUpdate() {// 經過打印分析發現:此時頁面上的 DOM 節點,都是舊的,應該慎重操作,因為你可能操作的是舊DOM// console.log(document.getElementById('myh3').innerHTML)console.log(this.refs.mymyh3.innerHTML);}// 組件完成了更新。此時,state 中的數據、虛擬DOM、頁面上的DOM,都是最新的,此時,你可以放心大膽的去操作頁面了componentDidUpdate() {console.log(this.refs.mymyh3.innerHTML);}
}
上方代碼中,componentWillUpdate() 和 componentDidUpdate() 方法里的代碼,就是我們這一段要舉的例子。
需要注意的是,<h3 id="myh3" ref="mymyh3">
這部分代碼中,屬性名只能小寫,不能大寫。
工程文件:
- ReactDemo.zip
五、生命周期函數:componentWillReceiveProps()
當子組件第一次被渲染到頁面上的時候,不會觸發這個 函數。
只有當父組件中,通過 某些 事件,重新修改了 傳遞給 子組件的 props 數據之后,才會觸發 componentWillReceiveProps。
代碼舉例:
(1)index.html:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Document</title>
</head><body><!-- 容器,通過 React 渲染得到的 虛擬DOM,會呈現到這個位置 --><div id="app"></div>
</body></html>
(2)main.js:(引入組件)
// JS打包入口文件
// 1. 導入包
import React from "react";
import ReactDOM from "react-dom";import MyParent from "./components/TestReceiveProps.jsx";// 使用 render 函數渲染 虛擬DOM
ReactDOM.render(<div><MyParent></MyParent></div>,document.getElementById("app")
);
(3)TestReceiveProps.jsx:(組件的定義)
import React from "react";// 父組件
export default class Parent extends React.Component {constructor(props) {super(props);this.state = {msg: "這是父組件中的 msg 消息"};}render() {return (<div><h1>這是父組件</h1><inputtype="button"value="點擊修改父組件的 MSG"onClick={this.changeMsg}/><hr />{/* 在父組件 Parent 中引用子組件 Son */}<Son pmsg={this.state.msg} /></div>);}changeMsg = () => {this.setState({msg: "修改組件的msg為新的值"});};
}// 子組件
class Son extends React.Component {constructor(props) {super(props);this.state = {};}render() {return (<div><h3>這是子組件 --- {this.props.pmsg}</h3></div>);}// 組件將要接收外界傳遞過來的新的 props 屬性值// 當子組件第一次被渲染到頁面上的時候,不會觸發這個 函數;// 只有當 父組件中,通過 某些 事件,重新修改了 傳遞給 子組件的 props 數據之后,才會觸發 componentWillReceivePropscomponentWillReceiveProps(nextProps) {// console.log('被觸發了!');// 注意: 在 componentWillReceiveProps 被觸發的時候,如果我們使用 this.props 來獲取屬性值,這個屬性值,不是最新的,是上一次的舊屬性值// 如果想要獲取最新的屬性值,需要通過 componentWillReceiveProps 的參數列表來獲取console.log(this.props.pmsg + " ---- " + nextProps.pmsg);}
}
上方代碼中,我們在組件 Parent 中引入了子組件 Son。重點注意 componentWillReceiveProps()函數 的注釋部分。