網站首頁 編程語言 正文
組件組件實例的三大核心屬性-State
狀態 state 是組件實例對象最重要的屬性之一,它的值是一個對象,可以包含多個 key-value 的組合。
當組件中的一些數據在某些時刻發生變化時,就需要使用 state 來跟蹤狀態。state 是私有的,并且完全受控于當前組件,除了擁有并設置了它的組件,其他組件都無法訪問。
組件被稱為狀態機,通過更新組件的 state 來重新渲染組件,更新對應的頁面顯示。
this.props 和 this.state 是 React 本身設置的,且都擁有特殊的含義,但是其實可以向類組件中隨意添加不參與數據流的額外字段(比如 this.timerID
)。
state 和 props 之間最重要的區別是:
- props 由父組件傳入,而 state 由組件本身管理。
- 組件不能修改 props,但可以修改 state。
class Weather extends React.Component{ constructor(props) { super(props) // 初始化 state this.state = { isHot: false, } } // state可以簡寫成如下形式 // 原因是:類中可以直接寫賦值語句,實際上就是直接給實例對象上添加屬性 state = { isHot: false, } componentDidMount() { // 更改 state this.setState({ isHot: !this.state.isHot, }) } ... }
State 不可以直接修改
初始化 state 之后,在其他地方不可以直接修改 state,而是應該使用 React 內置的一個 API:setState() 來修改。
constructor() 只初始化的時候調用一次。
render() 會調用 1+n 次,1是初始化,n 是狀態更新的次數(也就是說,每次 setState() 之后, React 都會調用一次 render())。
// Wrong,此代碼不會重新渲染組件 this.state.comment = 'Hello'; // Correct this.setState({comment: 'Hello'});
setState() 有兩種寫法:
setState(nextState, [callback]):對象式的 setState。
參數:
- nextState:將要設置的新狀態,該狀態會和當前的 state 合并。
- callback:可選參數,回調函數。該函數會在狀態更新完畢,且界面也更新后(render() 后)調用。
this.setState({ count: this.state.count +1, }, () => { console.log(this.state.count) })
setState(updater, [callback]):函數式的 setState。
參數:
- updater:是一個函數,可以接收到 state 和 props 作為參數,返回值為將要設置的新狀態。
- callback:可選參數,回調函數。該函數會在狀態更新完畢,且界面也更新后(render() 后)調用。
this.setState((state, props) => ({ count: state.count +1, }), () => { console.log(this.state.count) })
對象式的 setState 是函數式的 setState 的簡寫方式(語法糖)。這兩種寫法的使用原則:
如果新狀態不依賴于原狀態,使用對象方式;如果新狀態依賴于原狀態,使用函數方式。如果需要在 setState() 執行后獲取最新的狀態數據,要在第二個參數 callback 函數中讀取。
State 的更新是合并
setState() 的更新是合并,不是替換。
constructor(props) { super(props); // state 包含幾個獨立的變量 this.state = { isHot: false, wind: '微風', } } componentDidMount() { // 此處調用 setState() 更新了 isHot 的值,但是 wind 的值也并沒有丟失,所以說明更新的這個動作是合并 this.setState({ isHot: !this.state.isHot, }) }
State 的更新可能是異步的
出于性能考慮,React 可能會把多個 setState() 調用合并成一個調用。
因為 this.props 和 this.state 可能會異步更新,所以不要依賴他們的值來更新下一個狀態。要解決這個問題,可以讓 setState() 接收一個函數而不是一個對象。
// 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 值 })
組件實例對象的三大核心屬性-Props
當 React 元素為用戶的自定義組件時,它會將所接收的標簽屬性及子組件轉換為單個對象傳遞給組件,這個對象被稱之為 “props”。
props 是 React 組件的輸入。它們是組件外部向組件內部傳遞變化的數據。
props 是只讀的,組件無論是使用函數組件還是類組件,都決不能修改自身的 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> ) } } // 函數式組件 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 的簡寫方法(或者叫批量傳遞標簽屬性): // 原生 JS 中擴展運算符是不能展開對象的。 // 由于 React 和 Babel 的原因,擴展運算符可以展開對象,但僅僅適用于標簽屬性的傳遞,別的地方不支持。 ReactDOM.render(<Person {...{ name: 'jerry', age: 19, sex: '男' }} />, document.getElementById('test'))
props.children
每個組件都可以獲取到 props.children,它包含組件的開始標簽和結束標簽之間的內容。
<Welcome>Hello world!</Welcome> // 不寫標簽體,寫成 children 標簽屬性也可以 <Welcome children='Hello world!'></Welcome> // 在 Welcome 組件中獲取 props.children,就可以得到字符串 Hello world! function Welcome(props) { return <p>{props.children}</p>; }
使用defaultProps設置默認的prop值
可以通過配置特定的 defaultProps 屬性來定義 props 的默認值。
// 給組件加上 defaultProps 的屬性 Person.defaultProps = { title: '我是詳情' } // 簡寫:簡寫的這種方式只適用于類組件,因為函數式組件中是沒有 static 的 class Person extends React.Component{ static defaultProps = { title: '我是詳情' } }
使用propTypes進行類型檢查
PropTypes 提供一系列驗證器,可用于確保組件接收到的數據類型是有效的。當傳入的 prop 值類型不正確時,JavaScript 控制臺將會顯示警告。
propTypes 類型檢查發生在 defaultProps 賦值后,所以類型檢查也適用于 defaultProps。
出于性能方面的考慮,propTypes 僅在開發模式下進行檢查。
// 只要給組件加上 propTypes 屬性,React 就會認為是在加規則 Person.propTypes = { // React.PropTypes 是 React 內置的屬性 title: React.PropTypes.string.isRequired, // 錯誤 // 自 React v15.5 起,React.PropTypes 已移入另一個包中,需要的話要使用`import PropTypes from 'prop-types'`引入,引入之后全局就會有了一個對象 PropTypes title: PropTypes.string.isRequired, // 正確 speak: PropTypes.func, } /// 簡寫:簡寫的這種方式只適用于類組件,因為函數式組件中是沒有 static 的 class Person extends React.Component{ static propTypes = { title: PropTypes.string.isRequired, } }
組件實例對象的三大核心屬性-Refs
PS:勿過度使用 Refs
組件內的標簽可以定義 ref 屬性來標識自己,都會被收集到組件實例對象的 refs 屬性下,這樣,通過 this.refs.ref屬性 就可以訪問到 ref 當前所處的真實節點。
無法在函數式組件上使用 ref 屬性。
Ant Design 中很多組件都獲取不到 ref,可以包裹或內嵌一層自己創建的元素以獲取 ref。
字符串形式的Ref
React 不推薦使用字符串形式的 ref,它已過時并可能會在未來的版本中被移除,這種方式存在一些效率上的問題。
class Demo extends React.Component { showData = () => { console.log(this) // 打印可以看到組件的實例對象上 this 有 refs 屬性,屬性值是 key-value 的對象 ,其中有一個key 就是 input1,value 是 ref 當前所處的真實節點。 // 訪問 refs alert(this.res.input1.value) } render() { return ( <div> // 創建、綁定 refs <input ref="input1" /> <button onClick={this.showData}>點擊</button> </div> ) } }
回調函數形式的Ref
如果 ref 回調函數是以內聯函數的方式定義的,在更新過程中它會被執行兩次,第一次傳入參數 null,第二次才會傳入 DOM 元素。這是因為在每次 render 渲染時都會創建一個新的函數實例,所以 React 會首先清空舊的 ref,然后才會設置新的。這個問題大多數情況下是無關緊要的。
初次渲染時不會,因為初次渲染時沒有舊的 ref 需要去清空。
class Demo extends React.Component { showData = () => { // 訪問 refs alert(this.input1.value) } render() { return ( <div> // 創建、綁定 refs // render 方法執行的時候會自動調用 ref 的回調函數,并且會把當前所處的真實節點作為參數傳遞進去,然后將這個節點賦值給組件實例自身的一個自定義屬性上 <input ref={c => this.input1 = c} /> <button onClick={this.showData}>點擊</button> </div> ) } }
通過將 ref 的回調函數定義成類的綁定函數的方式可以避免上述問題。
class Demo extends React.Component { setInputRef = (c) => { // 綁定 refs this.input1 = c } showData = () => { // 訪問 refs alert(this.input1.value) } render() { return ( <div> // 創建 refs // 更新時也不會重復觸發 setInputRef,因為它已經放在實例自身了 <input ref={this.setInputRef} /> <button onClick={this.showData}>點擊</button> </div> ) } }
createRef
React.createRef() 是 React 內置的一個 API,調用后可以返回一個容器,該容器存儲被 ref 所標識的節點。該容器是專人專用的。
class Demo extends React.Component { // 創建 refs myRef = React.createRef() showData = () => { // 訪問 refs alert(this.myRef.current.value) } render() { return ( <div> // 綁定 refs // 下面一行代碼在執行的時候,React 發現了 ref 屬性,并且發現屬性值是用 createRef 創建出來的一個容器,這時, React 會把當前 ref 所在的那個節點直接存儲到那個容器里面 <input ref={this.myRef} /> <button onClick={this.showData}>點擊</button> </div> ) } }
訪問Refs
當 ref 被傳遞給 render 中的元素時,對該節點的引用可以在 ref 的 current 屬性中被訪問。
ref 的值根據節點
Refs 轉發
Refs 轉發是一個可選特性,其允許某些組件接收 ref,并將其向下傳遞給子組件。
ref 轉發不僅限于 DOM 組件,也可以轉發 refs 到 class 組件實例。
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,然后轉發到它渲染的 DOM button。這樣,使用 FancyButton 的組件可以獲取底層 DOM 節點 button 的 ref ,并在必要時訪問,就像其直接使用 DOM button 一樣。
上述代碼的執行步驟如下:
- 通過調用 React.createRef 創建了一個 React ref 并將其賦值給 ref 變量;
- 通過指定 ref 為 JSX 屬性,將其向下傳遞給
<FancyButton ref={ref}>
; - React 傳遞 ref 給 forwardRef 內函數
(props, ref) => ...
,作為其第二個參數; - 向下轉發該 ref 參數到
<button ref={ref}>
,將其指定為 JSX 屬性; - 當 ref 掛載完成,ref.current 將指向
<button>
DOM 節點;
原文鏈接:https://blog.csdn.net/wsln_123456/article/details/112005521
相關推薦
- 2022-10-13 Pygame?zero集合_python
- 2022-09-15 C語言實現簡單的推箱子小游戲_C 語言
- 2022-08-15 詳解Redis分布式鎖的原理與實現_Redis
- 2022-08-31 在.Net?Framework應用中請求HTTP2站點的問題解析_實用技巧
- 2023-04-14 jupyter-lab設置自啟動及遠程連接開發環境_python
- 2022-06-16 python遺傳算法之單/多目標規劃問題_python
- 2022-04-20 Python設計模式結構型享元模式_python
- 2022-07-21 Pandas常用數據結構
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支