React組件實(shí)例三大核心屬性State props Refs詳解
組件組件實(shí)例的三大核心屬性-State
狀態(tài) state 是組件實(shí)例對象最重要的屬性之一,它的值是一個對象,可以包含多個 key-value 的組合。
當(dāng)組件中的一些數(shù)據(jù)在某些時刻發(fā)生變化時,就需要使用 state 來跟蹤狀態(tài)。state 是私有的,并且完全受控于當(dāng)前組件,除了擁有并設(shè)置了它的組件,其他組件都無法訪問。
組件被稱為狀態(tài)機(jī),通過更新組件的 state 來重新渲染組件,更新對應(yīng)的頁面顯示。
this.props 和 this.state 是 React 本身設(shè)置的,且都擁有特殊的含義,但是其實(shí)可以向類組件中隨意添加不參與數(shù)據(jù)流的額外字段(比如 this.timerID)。
state 和 props 之間最重要的區(qū)別是:
- props 由父組件傳入,而 state 由組件本身管理。
- 組件不能修改 props,但可以修改 state。
class Weather extends React.Component{
constructor(props) {
super(props)
// 初始化 state
this.state = {
isHot: false,
}
}
// state可以簡寫成如下形式
// 原因是:類中可以直接寫賦值語句,實(shí)際上就是直接給實(shí)例對象上添加屬性
state = {
isHot: false,
}
componentDidMount() {
// 更改 state
this.setState({
isHot: !this.state.isHot,
})
}
...
}State 不可以直接修改
初始化 state 之后,在其他地方不可以直接修改 state,而是應(yīng)該使用 React 內(nèi)置的一個 API:setState() 來修改。
constructor() 只初始化的時候調(diào)用一次。
render() 會調(diào)用 1+n 次,1是初始化,n 是狀態(tài)更新的次數(shù)(也就是說,每次 setState() 之后, React 都會調(diào)用一次 render())。
// Wrong,此代碼不會重新渲染組件
this.state.comment = 'Hello';
// Correct
this.setState({comment: 'Hello'});setState() 有兩種寫法:
setState(nextState, [callback]):對象式的 setState。
參數(shù):
- nextState:將要設(shè)置的新狀態(tài),該狀態(tài)會和當(dāng)前的 state 合并。
- callback:可選參數(shù),回調(diào)函數(shù)。該函數(shù)會在狀態(tài)更新完畢,且界面也更新后(render() 后)調(diào)用。
this.setState({
count: this.state.count +1,
}, () => {
console.log(this.state.count)
})
setState(updater, [callback]):函數(shù)式的 setState。
參數(shù):
- updater:是一個函數(shù),可以接收到 state 和 props 作為參數(shù),返回值為將要設(shè)置的新狀態(tài)。
- callback:可選參數(shù),回調(diào)函數(shù)。該函數(shù)會在狀態(tài)更新完畢,且界面也更新后(render() 后)調(diào)用。
this.setState((state, props) => ({
count: state.count +1,
}), () => {
console.log(this.state.count)
})
對象式的 setState 是函數(shù)式的 setState 的簡寫方式(語法糖)。這兩種寫法的使用原則:
如果新狀態(tài)不依賴于原狀態(tài),使用對象方式;如果新狀態(tài)依賴于原狀態(tài),使用函數(shù)方式。如果需要在 setState() 執(zhí)行后獲取最新的狀態(tài)數(shù)據(jù),要在第二個參數(shù) callback 函數(shù)中讀取。
State 的更新是合并
setState() 的更新是合并,不是替換。
constructor(props) {
super(props);
// state 包含幾個獨(dú)立的變量
this.state = {
isHot: false,
wind: '微風(fēng)',
}
}
componentDidMount() {
// 此處調(diào)用 setState() 更新了 isHot 的值,但是 wind 的值也并沒有丟失,所以說明更新的這個動作是合并
this.setState({
isHot: !this.state.isHot,
})
}
State 的更新可能是異步的
出于性能考慮,React 可能會把多個 setState() 調(diào)用合并成一個調(diào)用。
因?yàn)?this.props 和 this.state 可能會異步更新,所以不要依賴他們的值來更新下一個狀態(tài)。要解決這個問題,可以讓 setState() 接收一個函數(shù)而不是一個對象。
// Wrong
this.setState({
count: this.state.count + 1,
})
console.log(this.state.counter) //此時直接讀取獲取到的仍然是舊的 count 值
// Correct
this.setState({
count: this.state.count + 1,
}, () => {
console.log(this.state.counter) //此時讀取獲取到的是新的 count 值
})
組件實(shí)例對象的三大核心屬性-Props
當(dāng) React 元素為用戶的自定義組件時,它會將所接收的標(biāo)簽屬性及子組件轉(zhuǎn)換為單個對象傳遞給組件,這個對象被稱之為 “props”。
props 是 React 組件的輸入。它們是組件外部向組件內(nèi)部傳遞變化的數(shù)據(jù)。
props 是只讀的,組件無論是使用函數(shù)組件還是類組件,都決不能修改自身的 props。
// 類組件
class Person extends React.Component{
render(){
const {name, age, sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性別:{sex}</li>
<li>年齡:{age+1}</li>
</ul>
)
}
}
// 函數(shù)式組件
function Person(props){
const {name, age, sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性別:{sex}</li>
<li>年齡:{age+1}</li>
</ul>
)
}
ReactDOM.render(<Person name="jerry" age={19} sex="男"/>, document.getElementById('test'))
// 批量傳遞 props 的簡寫方法(或者叫批量傳遞標(biāo)簽屬性):
// 原生 JS 中擴(kuò)展運(yùn)算符是不能展開對象的。
// 由于 React 和 Babel 的原因,擴(kuò)展運(yùn)算符可以展開對象,但僅僅適用于標(biāo)簽屬性的傳遞,別的地方不支持。
ReactDOM.render(<Person {...{
name: 'jerry',
age: 19,
sex: '男'
}} />, document.getElementById('test'))
props.children
每個組件都可以獲取到 props.children,它包含組件的開始標(biāo)簽和結(jié)束標(biāo)簽之間的內(nèi)容。
<Welcome>Hello world!</Welcome>
// 不寫標(biāo)簽體,寫成 children 標(biāo)簽屬性也可以
<Welcome children='Hello world!'></Welcome>
// 在 Welcome 組件中獲取 props.children,就可以得到字符串 Hello world!
function Welcome(props) {
return <p>{props.children}</p>;
}
使用defaultProps設(shè)置默認(rèn)的prop值
可以通過配置特定的 defaultProps 屬性來定義 props 的默認(rèn)值。
// 給組件加上 defaultProps 的屬性
Person.defaultProps = {
title: '我是詳情'
}
// 簡寫:簡寫的這種方式只適用于類組件,因?yàn)楹瘮?shù)式組件中是沒有 static 的
class Person extends React.Component{
static defaultProps = {
title: '我是詳情'
}
}
使用propTypes進(jìn)行類型檢查
PropTypes 提供一系列驗(yàn)證器,可用于確保組件接收到的數(shù)據(jù)類型是有效的。當(dāng)傳入的 prop 值類型不正確時,JavaScript 控制臺將會顯示警告。
propTypes 類型檢查發(fā)生在 defaultProps 賦值后,所以類型檢查也適用于 defaultProps。
出于性能方面的考慮,propTypes 僅在開發(fā)模式下進(jìn)行檢查。
// 只要給組件加上 propTypes 屬性,React 就會認(rèn)為是在加規(guī)則
Person.propTypes = {
// React.PropTypes 是 React 內(nèi)置的屬性
title: React.PropTypes.string.isRequired, // 錯誤
// 自 React v15.5 起,React.PropTypes 已移入另一個包中,需要的話要使用`import PropTypes from 'prop-types'`引入,引入之后全局就會有了一個對象 PropTypes
title: PropTypes.string.isRequired, // 正確
speak: PropTypes.func,
}
/// 簡寫:簡寫的這種方式只適用于類組件,因?yàn)楹瘮?shù)式組件中是沒有 static 的
class Person extends React.Component{
static propTypes = {
title: PropTypes.string.isRequired,
}
}
組件實(shí)例對象的三大核心屬性-Refs
PS:勿過度使用 Refs
組件內(nèi)的標(biāo)簽可以定義 ref 屬性來標(biāo)識自己,都會被收集到組件實(shí)例對象的 refs 屬性下,這樣,通過 this.refs.ref屬性 就可以訪問到 ref 當(dāng)前所處的真實(shí)節(jié)點(diǎn)。
無法在函數(shù)式組件上使用 ref 屬性。
Ant Design 中很多組件都獲取不到 ref,可以包裹或內(nèi)嵌一層自己創(chuàng)建的元素以獲取 ref。
字符串形式的Ref
React 不推薦使用字符串形式的 ref,它已過時并可能會在未來的版本中被移除,這種方式存在一些效率上的問題。
class Demo extends React.Component {
showData = () => {
console.log(this) // 打印可以看到組件的實(shí)例對象上 this 有 refs 屬性,屬性值是 key-value 的對象 ,其中有一個key 就是 input1,value 是 ref 當(dāng)前所處的真實(shí)節(jié)點(diǎn)。
// 訪問 refs
alert(this.res.input1.value)
}
render() {
return (
<div>
// 創(chuàng)建、綁定 refs
<input ref="input1" />
<button onClick={this.showData}>點(diǎn)擊</button>
</div>
)
}
}
回調(diào)函數(shù)形式的Ref
如果 ref 回調(diào)函數(shù)是以內(nèi)聯(lián)函數(shù)的方式定義的,在更新過程中它會被執(zhí)行兩次,第一次傳入?yún)?shù) null,第二次才會傳入 DOM 元素。這是因?yàn)樵诿看?render 渲染時都會創(chuàng)建一個新的函數(shù)實(shí)例,所以 React 會首先清空舊的 ref,然后才會設(shè)置新的。這個問題大多數(shù)情況下是無關(guān)緊要的。
初次渲染時不會,因?yàn)槌醮武秩緯r沒有舊的 ref 需要去清空。
class Demo extends React.Component {
showData = () => {
// 訪問 refs
alert(this.input1.value)
}
render() {
return (
<div>
// 創(chuàng)建、綁定 refs
// render 方法執(zhí)行的時候會自動調(diào)用 ref 的回調(diào)函數(shù),并且會把當(dāng)前所處的真實(shí)節(jié)點(diǎn)作為參數(shù)傳遞進(jìn)去,然后將這個節(jié)點(diǎn)賦值給組件實(shí)例自身的一個自定義屬性上
<input ref={c => this.input1 = c} />
<button onClick={this.showData}>點(diǎn)擊</button>
</div>
)
}
}
通過將 ref 的回調(diào)函數(shù)定義成類的綁定函數(shù)的方式可以避免上述問題。
class Demo extends React.Component {
setInputRef = (c) => {
// 綁定 refs
this.input1 = c
}
showData = () => {
// 訪問 refs
alert(this.input1.value)
}
render() {
return (
<div>
// 創(chuàng)建 refs
// 更新時也不會重復(fù)觸發(fā) setInputRef,因?yàn)樗呀?jīng)放在實(shí)例自身了
<input ref={this.setInputRef} />
<button onClick={this.showData}>點(diǎn)擊</button>
</div>
)
}
}
createRef
React.createRef() 是 React 內(nèi)置的一個 API,調(diào)用后可以返回一個容器,該容器存儲被 ref 所標(biāo)識的節(jié)點(diǎn)。該容器是專人專用的。
class Demo extends React.Component {
// 創(chuàng)建 refs
myRef = React.createRef()
showData = () => {
// 訪問 refs
alert(this.myRef.current.value)
}
render() {
return (
<div>
// 綁定 refs
// 下面一行代碼在執(zhí)行的時候,React 發(fā)現(xiàn)了 ref 屬性,并且發(fā)現(xiàn)屬性值是用 createRef 創(chuàng)建出來的一個容器,這時, React 會把當(dāng)前 ref 所在的那個節(jié)點(diǎn)直接存儲到那個容器里面
<input ref={this.myRef} />
<button onClick={this.showData}>點(diǎn)擊</button>
</div>
)
}
}
訪問Refs
當(dāng) ref 被傳遞給 render 中的元素時,對該節(jié)點(diǎn)的引用可以在 ref 的 current 屬性中被訪問。
ref 的值根據(jù)節(jié)點(diǎn)
Refs 轉(zhuǎn)發(fā)
Refs 轉(zhuǎn)發(fā)是一個可選特性,其允許某些組件接收 ref,并將其向下傳遞給子組件。
ref 轉(zhuǎn)發(fā)不僅限于 DOM 組件,也可以轉(zhuǎn)發(fā) refs 到 class 組件實(shí)例。
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
FancyButton 使用 React.forwardRef 來獲取傳遞給它的 ref,然后轉(zhuǎn)發(fā)到它渲染的 DOM button。這樣,使用 FancyButton 的組件可以獲取底層 DOM 節(jié)點(diǎn) button 的 ref ,并在必要時訪問,就像其直接使用 DOM button 一樣。
上述代碼的執(zhí)行步驟如下:
- 通過調(diào)用 React.createRef 創(chuàng)建了一個 React ref 并將其賦值給 ref 變量;
- 通過指定 ref 為 JSX 屬性,將其向下傳遞給
<FancyButton ref={ref}>; - React 傳遞 ref 給 forwardRef 內(nèi)函數(shù)
(props, ref) => ...,作為其第二個參數(shù); - 向下轉(zhuǎn)發(fā)該 ref 參數(shù)到
<button ref={ref}>,將其指定為 JSX 屬性; - 當(dāng) ref 掛載完成,ref.current 將指向
<button>DOM 節(jié)點(diǎn);
到此這篇關(guān)于React組件實(shí)例三大核心屬性State props Refs詳解的文章就介紹到這了,更多相關(guān)React組件state props refs內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react-native 封裝視頻播放器react-native-video的使用
本文主要介紹了react-native 封裝視頻播放器react-native-video的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-01-01
React源碼state計(jì)算流程和優(yōu)先級實(shí)例解析
這篇文章主要為大家介紹了React源碼state計(jì)算流程和優(yōu)先級實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
ReactNative實(shí)現(xiàn)弧形拖動條的代碼案例
本文介紹了ReactNative實(shí)現(xiàn)弧形拖動條,本組件使用到了react-native-svg和PanResponder,結(jié)合示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-02-02
解決React報(bào)錯Parameter 'props' implicitly&nb
這篇文章主要為大家介紹了React報(bào)錯Parameter 'props' implicitly has an 'any' type的解決處理方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
React styled-components設(shè)置組件屬性的方法
這篇文章主要介紹了styled-components設(shè)置組件屬性的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
hooks寫React組件的5個注意細(xì)節(jié)詳解
這篇文章主要為大家介紹了hooks寫React組件的5個需要注意的細(xì)節(jié)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03

