組件實例三大屬性


組件實例三大屬性

一、三大屬性之一:state

1、在構造器中初始化state

默認狀態下React.Components會給我們定義構造器(類似於無參構造函數一樣),但是默認是把state設置為null的,那么如果我們要自定義初始化的state的話,那么我們就要像(有參構造函數一樣)自定義構造函數了

 

如何自定義構造函數呢?

先上代碼:

class Weather extends React.Component {
        constructor(props) {
            super(props)
            this.state = {isHot: false}
            this.changeWeacher = this.changeWeacher.bind(this)
        }
        render() {
            return <h1 onClick={this.changeWeacher}>今天天氣很{this.state.isHot ? '炎熱' : '涼爽'}</h1>
        }
        // 不寫 function
        changeWeacher() {
            console.log(this)
        }
    }
 

其中的構造函數模塊:

 constructor(props) {
     super(props)
     this.state = {isHot: false}
     this.changeWeacher = this.changeWeacher.bind(this)
}

 

一個重要的細節:

自定義構造函數,必須要執行

super(props)

 

為什么?

並且 為什么super()要放在構造函數最上面執行呢?

ES6語法中,super指代的其實是父類的構造函數,也就是React.Component的構造函數了,

  • 在你調用super( ) 之前,你無法在構造函數中使用this

  • 執行 super(props) 可以使基類 React.Component 初始化 this.props。

  • 另外一個疑問:有時候我們不傳 props,只執行 super(),或者沒有設置 constructor 的情況下,依然可以在組件內使用 this.props,為什么呢?

    • 其實 React 在組件實例化的時候,馬上又給實例設置了一遍 props:

      // React 內部
      const instance = new YourComponent(props);
      instance.props = props;

       

    • 雖然 React 會在組件實例化的時設置一遍 props,但在 super 調用一直到構造函數結束之前,this.props 依然是未定義的(直接報錯了)

      class Button extends React.Component {
        constructor(props) {
          super(); // ? 我們忘了傳入 props
          console.log(props);      // ✅ {}
          console.log(this.props); // ? undefined
        }
        // ...
      }

       

 

 

然后因為state要是對象的模式,所以通過以下語句進行初始化

 this.state = {isHot: false}

 

 

拓展:類中的方法!

 render() {
   return <h1 onClick={this.changeWeacher()}>今天天氣很{this.state.isHot ? '炎熱' : '涼爽'}</h1>
 }

 

如果是通過 this.changeWeacher() 的話 報錯

因為在{ } 內是js語句,所以this.changeWeacher()是直接執行了函數,那么onclick得到的就是這個函數執行的結果了,所以這種方式的話,那么這個函數是一個柯里化函數

  • 柯里化函數:該函數接收一個函數作為參數(比如數組的map方法),或者是該函數返回值是一個函數

如果我們定義函數的時候直接通過:

changeWeacher() {
    console.log(this)
    }

 

那么這個時候this是undefined的,因為在babal的模式下,也就是嚴格模式下,changeWeacher函數里面的this是直接執行全局的,但是嚴格模式下不允許這個發生,所以執行的就是undefined

  • 代碼中通過如下方式(通過bind顯示硬綁定this,讓this執行的是該class類的實例了)

this.changeWeacher = this.changeWeacher.bind(this)

 

 

在函數中訪問和修改state

當該函數的this不管是通過 箭頭函數 還是通過顯示綁定的方式讓this執行了該實例的話,就可以通過this來訪問state了

changeWeacher() {
    const isHot = this.state.isHot
    this.setState({isHot: !isHot}) 
}

 

並且只能通過 this.setState的方式改變state,直接賦值操作改變的話,改變不了狀態的(賦值操作可以改變頁面數值,但是內部的狀態是沒有改變的)

 

state的簡寫方式

class Weather extends React.Component {
            state = {isHot: false}

            render() {
                return <h1 onClick={this.changeWeacher}>今天天氣很{this.state.isHot ? '炎熱' : '涼爽'}</h1>
            }

            changeWeacher = () => {
               const isHot = this.state.isHot
               this.setState({isHot: !isHot}) 
            }
        }

 

  • 不適用構造函數初始化state,直接像定義private屬性一樣,直接定義類的屬性

  • 通過箭頭函數的方式定義函數(因為即使在babel嚴格模式下,箭頭函數不會收到嚴格模式的約束,在箭頭函數中使用this訪問屬性的話,當前作用域找不到的話,就在外面作用域找

    • 所以就可以在箭頭函數的this中直接訪問實例中定義的state了

 

二、三大屬性之二:props

 

props的基本使用

<script type="text/babel">
        class Person extends React.Component{
            render() {
                return (
                    <ul>
                        <li>年級1:{this.props.name}</li>
                        <li>年級2:{this.props.sex}</li>
                        <li>年級3:{this.props.age}</li>
                    </ul>
                )
            }
        }
        // ReactDOM.render(<Person age="19" />, document.getElementById('test'))
        // ReactDOM.render(<Person age={19}/>, document.getElementById('test'))

        const p = {name : 'gogocj', age: '19', sex: '男'}
        ReactDOM.render(<Person {...p} />, document.getElementById('test'))
    </script>

 

  • 在類中中直接通過this.props訪問傳遞過來的參數

    • 如果是在jsx中的話,就要在 { } 中來訪問this.props

  • 傳遞參數相關

    • 如果想要傳輸數字的話,要通過 <Person age={19}/>,也就是通過一個{ } 因為在{ }中式js語句,所以19就是js語句中的數字了

    • 通過{ ...p } 三點運算展開符的方式來傳遞props

 

限制props的類型和默認值

class Person extends React.Component{
            ........
        }
        Person.propTypes = {
            name: PropTypes.string.isRequired,
            speak: PropTypes.func
        }
        Person.defaultProps = {
            sex: '未知'
        }

 

使用繼承了React.Component的類自帶的 propTypes屬性

  • 要求是串聯的:

    PropTypes.string.isRequired  // 表示類型是字符串,並且是必須傳的

     

  • 默認值通過 自帶的defaultProps屬性

 

簡寫方式

上面都是直接通過Person.propTypes的方式來對規定類型限制的:

但是Person就是當前的類,所以完全可以省略Person,直接在這個類的內部定義一個static對象就可以了

class Person extends React.Component{
        ............
        static propTypes = {
            name: PropTypes.string.isRequired,
            speak: PropTypes.func
        }
        static defaultProps = {
            sex: '未知'
        }
}

 

 

在構造器中使用props

constructor(props) {
    super(props)
    // 使用props
}

 

  • 如果要在構造器中使用的話就必須寫 super(props) ,不然在構造器中使用props的話,就會直接的報錯了

  • 也就是說,構造器中不適用props就可以不定義,使用的話就要super一下

 

 

三、三大屬性之三:refs

前言:

React的誕生很多都是為了減少對document的使用,而我們如果在js中要獲取到對應元素的話,傳統的方法都是直接使用document的getlementbyid,byClass等等,到那時在React為了減少document操作,使用的是refs

 

字符串類型的refs

  • class Demo extends React.Component{
                showData = () => {
                   const {input01} = this.refs
                   alert(input01.value)
                }
                render() {
                    return (
                        <div>
                            <input id="input1" ref="input01" type="text" placeholder="點擊按鈕提示數據"/>
                            <button onClick={this.showData}>點我提示左側的數據</button>
                        </div>
                    )
                }
            }

     

    我們通過在jsx中,用ref來表示jsx中程序員寫的虛擬DOM,但是我們通過this.refs獲取到的元素並不是虛擬DOM,而是虛擬DOM轉化成真實DOM之后的節點

  • 通過this.refs.input01就可以拿到這個input元素了

 

拓展:React對原生html的相關瘋轉

在原生里面使用 onclick、onblur等等,但是在React中使用的是onClick、onBlur等等

為什么呢?

React其實是在原生的onclick等等的基礎上,進行了相關兼容性的封裝,然后改了一下名字,也就是第二個單詞首字母大寫了,也就是onClick

 

回到函數形式的refs

前言:

字符串形式的ref可能在未來就廢除了,因為過多的給原生定義refs來獲取該元素信息,方便但是性能太低了

 class Demo extends React.Component{
            showData = () => {
               const {input01} = this
               alert(input01.value)
            }
            render() {
                return (
                    <div>
                        <input  ref={ c => this.input01 = c} type="text" placeholder="點擊按鈕提示數據"/>
                        <button onClick={this.showData}>點我提示左側的數據</button>
                    </div>
                )
            }
        }

 

  • 直接在ref中調用箭頭函數,參數就是該元素(代碼中用c表示),直接通過this.input01 = c吧這個元素掛載到this上了,因為是箭頭函數,所以此時的this執行的是該類實例。

 

使用內聯函數的ref

class Demo extends React.Component{
             saveInput = (c) => {
                this.input1 = c
                console.log('@',c)
            }
            render() {
                return (
                    <div>
                       <input ref={ this.saveInput } type="text"/>
                        <button onClick={this.showInfo}>點我</button>   
                    </div>
                )
            }
        }

 

但是這種內聯函數是有一個問題的

  • saveInput中:就是在狀態更新的時候會執行兩次,第一次c拿到的是null,第二次拿到的才是該元素,更新指的是狀態的更新,也就是再一次調用render函數,但是點擊和刷新就不會出現這個問題了 ,這是因為在每次渲染render的時候都會創建一個新的函數實例,所以React清空舊的並且設置新的。

 

另一種方式:React.createRef

class Demo extends React.Component{
    
            myRef1 = React.createRef()
            myRef2 = React.createRef()
            
            showData1 = () => {
               alert(this.myRef1.current.value)
            }
            showData2 = () => {
               alert(this.myRef2.current.value)
            }
            
            render() {
                return (
                    <div>
                        <input  ref={this.myRef1} type="text" placeholder="點擊按鈕提示數據1"/>
                        <button onClick={this.showData1}>點我提示左側的數據</button>
                        <input onBlur={this.showData2}  ref={this.myRef2} type="text" placeholder="失去焦點提示數據"/>
                    </div>
                )
            }
        }

 

  • ref={this.myRef} 調用之后,自動把該標簽放到這個容器里面

  • 但是該容器是“專人專用”的,如果多個標簽同時使用的話,那么后放進去的標簽就會把前面的頂掉了

  • 雖然這個是要用多少個就要掛載多少個在實例上,但是這種方式是目前react最推薦的一種方式了

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM