日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

React組件三大屬性之state,props,refs_React

作者:蠟筆雛田學代碼 ? 更新時間: 2022-09-15 編程語言

1.1基本理解和使用

1.1.1 使用React開發者工具調試

React Developer Tools

1.1.2 定義組件的方式

Ⅰ.函數式組件:

<script type="text/babel">
    // 1.創建函數式組件  (首字母必須大寫)
    function MyComponent() { //(函數必須有返回值)
        console.log(this)  //undefined (本來this指向的是window,但是由于babel翻譯完之后啟用es5的嚴格模式,自定義的函數里的this不讓指向window)  
      return <h2>我是用函數定義的組件(適用于【簡單組件】的定義)</h2>
    }
    // 2.渲染組件到頁面  (必須寫組件標簽)
    ReactDOM.render(<MyComponent />, document.getElementById('test'))
  </script>

執行了ReactDOM.render(…之后發生了什么?

1.React解析組件標簽,找到了MyComponent組件。

2.發現組件是使用函數定義的,隨后調用該函數,將返回的虛擬DOM轉為真實DOM,隨后呈現在頁面中。

類的基本知識復習移步到vscode

Ⅱ.類式組件:

復雜組件:如果組件是有狀態的,那么就是復雜組件。

<script type="text/babel">
    // 1.創建類式組件
    class MyComponent extends React.Component {
      render() {
        // render是放在哪里的?——MyComponent的原型對象上,供實例使用
        // render中的this是誰?——MyComponent的實例對象 <=> MyComponent組件實例對象
        console.log('render中的this是誰:', this)
        return <h2>我是用類定義的組件(適用于【復雜組件】的定義)</h2>
      }
    }
    // 渲染組件到頁面
    ReactDOM.render(<MyComponent />, document.getElementById('test'))

執行了ReactDOM.render(…之后發生了什么?

1.React解析組件標簽,找到了MyComponent組件。

2.發現組件是使用類定義的,隨后new出來該類的實例,并通過該實例調用到原型上的render方法。

3.將render返回的虛擬DOM轉為真實DOM,隨后呈現在頁面中。

1.1.3 注意

  • 組件名必須首字母大寫
  • 虛擬DOM元素只能有一個根標簽
  • 虛擬DOM元素必須有結束標簽

1.1.4 渲染類組件標簽的基本流程

  • React內部會創建組件實例對象
  • 調用render()返回得到虛擬DOM, 并解析為真實DOM
  • 插入到指定的頁面元素內部

1.2 組件實例的三大核心屬性之一:state

1.2.1 理解

  • state是組件對象最重要的屬性, 值是對象(可以包含多個key-value的組合)
  • 組件被稱為"狀態機", 通過更新組件的state,來更新對應的頁面顯示(重新渲染組件)
  • 數據存放在狀態里,來驅動對應頁面的顯示

1.2.2 案例

需求: 定義一個展示天氣信息的組件

  • 默認展示天氣炎熱 或 涼爽
  • 擊文字切換天氣

效果如下:

1.2.3 在類式組件使用state

<script type="text/babel">
    // 1.創建組件
    class Weather extends React.Component {
      // 借助構造器初始化狀態
      // 構造器調用了幾次?————1次
      constructor(props) {
        console.log('constructor')
        super(props)
        // 初始化狀態   
        this.state = { isHot: true, wind: '微風' }
        //解決changeWeather中this指向的問題
        this.changeWeather = this.changeWeather.bind(this)
        // 這是一個賦值語句,右邊的this.changeWeather是指順著原型鏈找到了changeWeather(),然后調用bind(),bind可以生成一個新的函數,改變this指向。括號中為傳入的this,指得就是類中的實例對象 
        // 拿到了原型上的changeWeather,通過bind生成了一個新的changeWeather掛在實例自身
      }
      // render調用了幾次?————1+n次 1是初始化的那次,n是狀態更新的次數
      render() {
        console.log('render')
        // 讀取狀態
        const { isHot, wind } = this.state
        //        react:將changeWeather調用的返回值賦值給onClick,不用加括號  
        //        原生js:onclick時調用changeWeather函數,要加括號
        return <h1 onClick={this.changeWeather}>今天天氣很{isHot ? '炎熱' : '涼爽'},{wind}</h1>
        //    含義是:這是一個賦值語句,把右邊這個函數交給onClick作為回調,
        //            等你點擊的時候,react幫你調changeWeather()函數
      }

      // changeWeather調用了幾次?————點幾次調幾次
      changeWeather() {
        console.log('changeWeather')
        // changeWeather放在哪里?——Weather的原型對象上,供實例使用
        // 通過Weather實例調用changeWeather時,changeWeather中的this就是Weather實例
        console.log(this)   //undefined
        // 因為changeWeather不是通過實例調用的,是直接調用,所以this不會指向 實例對象
        // 那么 changeWeather 的this 是指向 undefined還是 window呢
        // 是 undefined 因為 類中的局部函數默認開啟了嚴格模式(類自動開的,與babel無關),所以不能指向 window

        // 獲取原來的isHot值
        const isHot = this.state.isHot
        // 嚴重注意:狀態(state)里的數據不能直接進行更改,下面這行就是直接更改,react不認可!!!
        // this.state.isHot = !isHot  錯誤寫法

        // 嚴重注意:狀態必須通過setState進行修改,并且修改是一種合并,不是替換,只修改了isHot,wind不會丟失
        this.setState({ isHot: !isHot })
      }
    }
    // 2.渲染組件到頁面
    ReactDOM.render(<Weather />, document.getElementById('test'))

  </script>

1.2.4 在類式組件使用state的簡寫方式

<script type="text/babel">
    // 1.創建組件
    class Weather extends React.Component {
      // 初始化狀態時直接在類里面寫賦值語句
      state = { isHot: true, wind: '微風' }
      render() {
        const { isHot, wind } = this.state
        return <h1 onClick={this.changeWeather}>今天天氣很{isHot ? '炎熱' : '涼爽'},{wind}</h1>
      }

      // 自定義方法 ————在用類去創建一個組件時,組件里所有自定義的方法都要用 賦值語句+箭頭函數 的形式
      changeWeather = () => {   //箭頭函數沒有this,箭頭函數內的this指向其外側
        const isHot = this.state.isHot
        this.setState({ isHot: !isHot })
        console.log(this)
      }
    }
    ReactDOM.render(<Weather />, document.getElementById('test'))
  </script>

1.2.3 強烈注意

  • 組件中render方法中的this組件實例對象
  • 組件自定義的方法中this為undefined,如何解決?

①強制綁定this:通過函數對象的bind()
②箭頭函數 ()=>{}

狀態數據,不能直接修改或更新,狀態必須通過setState進行修改

1.3 組件實例的三大核心屬性之一:props

1.3.1 理解

  • 每個組件對象都會有props(properties 的簡寫)屬性
  • 組件標簽所有屬性都保存在props中 1.3.2 案例

需求: 自定義用來顯示一個人員信息的組件

  • 姓名必須指定,且為字符串類型
  • 性別為字符串類型,如果性別沒有指定,默認為男
  • 年齡為字符串類型,且為數字類型,默認值為18

效果如下:

1.3.3 作用

  • 通過標簽屬性從組件外向組件內傳遞變化的數據
  • 注意: 組件內部不要修改props數據,因為props是只讀的

1.3.4 在類式組件使用props

先從內部讀取某個屬性值:

//實例對象身上有個屬性props,需要傳值進去,那怎么傳呢?html標簽能寫標簽屬性(key:value),那么組件標簽(<Person/>)也能寫屬性
// 解構賦值 提前從props身上拿到這三個屬性 
const { name, age, sex } = this.props

對props中的屬性值進行類型限制和必要性限制:

第一種方式(React v15.5 開始已棄用):

Person.propTypes = {
 name: React.PropTypes.string.isRequired,
 age: React.PropTypes.number
}

第二種方式(新):使用prop-types庫進限制(需要引入prop-types庫)

//給Person加上propTypes屬性,react就能幫你限制了
//寫在Person類外面
Person.propTypes = {
  // 具體的propTypes規則,要去PropTypes(React里面內置的一個屬性)里面找
  name: PropTypes.string.isRequired, //限制name必傳,且為字符串
  age: PropTypes.number //限制age為數值
}

在類式組件使用props的簡寫方式

// 用static表示給類自身加上一個propTypes和defaultProps屬性,而不是給類的實例對象加屬性
// 寫在Person類里面
static propTypes = {
   name: PropTypes.string.isRequired,  //限制name必傳,且為字符串
   sex: PropTypes.string, //限制sex為字符串
   age: PropTypes.number, //限制age為數值
 }

static defaultProps = {
   sex: '男',  //sex默認值為不男不女
   age: 18  //age默認值為18
 }

擴展屬性: 將對象的所有屬性通過props傳遞

// 展開運算符在對對象使用時,應當注意以{}包裹起來
<Person {...person}/>
//...展開運算符具體運用看vscode

默認屬性值:

Person.defaultProps = {
  age: 18, //age默認值為18
  sex:'男'//sex默認值為男
}

組件類的構造函數:

//開發中很少寫構造器,能省則省
// 構造器是否接收props,是否傳遞給super,取決于:是否希望在構造器中通過this訪問props
constructor(props){
  // 只要寫了構造器,就一定要調用super(),一定要傳props
  super(props)
  console.log(props)//打印所有屬性
}

1.3.5 在函數式組件使用props

<script type="text/babel">
    // 創建組件
    //函數式組件能接收參數
    function Person(props) {
      // console.log(props)
      const { name, sex, age } = props
      return (
        <ul>
          <li>姓名:{name}</li>
          <li>性別:{sex}</li>
          <li>年齡:{age}</li>
        </ul>
      )
    }
    Person.propTypes = {
      name: PropTypes.string.isRequired,  //限制name必傳,且為字符串
      sex: PropTypes.string, //限制sex為字符串
      age: PropTypes.number, //限制age為數值
    }

    Person.defaultProps = {
      sex: '男',  //sex默認值為不男不女
      age: 18  //age默認值為18
    }
    ReactDOM.render(<Person name='旭旭' />, document.getElementById('test'))
  </script>

1.4 組件實例的三大核心屬性之一:refs與事件處理

1.4.1 理解

組件內的標簽可以定義ref屬性來標識自己(相當于原生里是id)

1.4.2 效果

需求: 自定義組件, 功能說明如下:

  • 點擊按鈕, 提示第一個輸入框中的值
  • 當第2個輸入框失去焦點時, 提示這個輸入框中的值

1.4.3 字符串形式的ref

<script type="text/babel">
    // 創建組件
    class Demo extends React.Component {
      // 展示左側輸入框的數據
      showData = () => {
        const { input1 } = this.refs
        alert(input1.value)
      }
      // 展示右側輸入框的數據
      showData2 = () => {
        const { input2 } = this.refs
        alert(input2.value)
      }

      render() {
        return (
          <div>
            <input ref="input1" type="text" placeholder="點擊按鈕提示數據" /> &nbsp;
            <button onClick={this.showData}>點我提示左側的數據</button> &nbsp;
            <input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦點提示數據" />
          </div>
        )
      }
    }
    //渲染組件
    ReactDOM.render(<Demo />, document.getElementById('test'))
  </script>

過時的API:String 類型的 Refs

如果你之前使用過 React,你可能了解過之前的 API 中的 string 類型的 ref 屬性,例如 "textInput"。你可以通過 this.refs.textInput 來訪問 DOM 節點。我們不建議使用它,因為 string 類型的 refs 存在 一些問題。它已過時并可能會在未來的版本被移除。

效果如下:

1.4.4 回調形式的ref

<script type="text/babel">
    // 創建組件
    class Demo extends React.Component {
      // 展示左側輸入框的數據
      showData = () => {
        const { input1 } = this
        alert(input1.value)
      }
      // 展示右側輸入框的數據
      showData2 = () => {
        const { input2 } = this
        alert(input2.value)
      }

      // 回調函數的特點:你定義的,別人調的,最終執行了
      // 回調函數的參數正是ref當前所處的那個input節點
      render() {
        return (
          <div>
            {/* 代碼執行步驟: */}
            {/* React加載Demo組件時,執行render函數內的jsx代碼,發現input中有ref屬性,屬性內容是一個箭頭函數,React就會幫我們調用這個回調函數,并且把當前的DOM傳進這個函數,這樣就可以接收到當前的DOM節點了,并把這個DOM放在組件實例自身上 */}
            {/* 箭頭函數接收到參數(當前的DOM節點)命名為(currentNode),將currentNode賦值給實例對象下的input1這個屬性 */}
            {/* 箭頭函數只有一個參數可以省略'()',箭頭函數右邊只有一條函數體可以省略'{}' */}
            {/*<input ref={currentNode => this.input1 = currentNode} type="<text>" placeholder="點擊按鈕提示數據" />&nbsp;*/}
            <input ref={(currentNode) => { this.input1 = currentNode }} type="text" placeholder="點擊按鈕提示數據" /> &nbsp;
            <button onClick={this.showData}>點我提示左側的數據</button> &nbsp;
            <input ref={(currentNode) => { this.input2 = currentNode }} onBlur={this.showData2} type="text" placeholder="失去焦點提示數據" />
          </div>
        )
      }
    }
    //渲染組件
    ReactDOM.render(<Demo />, document.getElementById('test'))
  </script>

效果如下:

1.4.5 回調ref中回調執行次數的問題(class的綁定函數)

<script type="text/babel">
    // 創建組件
    class Demo extends React.Component {

      state = { isHot: true }

      showInfo = () => {
        const { input1 } = this
        alert(input1.value)
      }

      changeWeather = () => {
        // 獲取原來的狀態
        const { isHot } = this.state
        // 更新狀態
        this.setState({ isHot: !isHot })
      }

      savaInput = (currentNode) => {
        this.input1 = currentNode;
      }

      render() {
        const { isHot } = this.state
        return (
          <div>
            <h1>今天天氣很{isHot ? '炎熱' : '涼爽'}</h1>
            {/* React在更新組件時,會先傳入null調用一次ref中的回調,以清空之前的ref;然后再傳入參數currentNode,以調用第二次。每更新一次組件,ref中的回調函數就會被調用兩次,一次傳入null,一次傳入參數currentNode。為了應對這種情況的出現,官方建議將ref的回調函數定義成 class 的綁定函數 的方式去避免上述的問題。 */}

            {/*內聯函數*/}
            {/*<input ref={(currentNode) => { this.input1 = currentNode; console.log('@', currentNode) }} type="text" /><br /><br />*/}
            <input ref={this.savaInput} type="text" /><br /><br />
            <button onClick={this.showInfo}>點我提示輸入的數據</button>&nbsp;
            <button onClick={this.changeWeather}>點我切換天氣</button>
          </div>
        )
      }
    }
    //渲染組件
    ReactDOM.render(<Demo />, document.getElementById('test'))
  </script>

React在更新組件時,會先傳入null調用一次ref中的回調,以清空之前的ref;然后再傳入參數currentNode,以調用第二次。每更新一次組件,ref中的回調函數就會被調用兩次,一次傳入null,一次傳入參數currentNode。為了應對這種情況的出現,官方建議將ref的回調函數定義成 class 的綁定函數 的方式去避免上述的問題。

效果如下:

1.4.6 createRef創建ref容器

<script type="text/babel">
    // 創建組件
    class Demo extends React.Component {
      myRef = React.createRef()
      myRef2 = React.createRef()
      /* React.createRef調用后可以返回一個容器,該容器可以存儲被ref所標識的節點,該容器是“專人專用”的,也就是,調用React.createRef()創建了一個容器,通過賦值語句賦值給實例自身名為myRef的屬性上 */
      // 展示左側輸入框的數據
      showData = () => {
        // console.log(this.myRef)
        alert(this.myRef.current.value)
      }
      // 展示右側輸入框的數據
      showData2 = () => {
        alert(this.myRef2.current.value)
      }

      // 回調函數的特點:你定義的,別人調的,最終執行了
      // 回調函數的參數正是ref當前所處的那個input節點
      render() {
        return (
          <div>
            {/* React執行render函數中的jsx代碼時,
            發現input上有一個ref屬性而且是通過createRef方法創建的,
            React就會把當前ref屬性所在的DOM節點放到之前創建的那個容器上,
            也就是把當前input這個DOM節點放到了實例自身名為myRef的容器上 */}
            {/* 可以簡寫成ref={this.myRef = React.createRef()} */}
            <input ref={this.myRef} type="text" placeholder="點擊按鈕提示數據" /> &nbsp;
            <button onClick={this.showData}>點我提示左側的數據</button> &nbsp;
            {/* 發生事件的元素正好是需要操作的元素本身,可以省略ref */}
            <input ref={this.myRef2} onBlur={this.showData2} type="text" placeholder="失去焦點提示數據" /> &nbsp;
          </div>
        )
      }
    }
    //渲染組件
    ReactDOM.render(<Demo />, document.getElementById('test'))
  </script>

效果如下:

1.4.7 事件處理

  • 通過onXxx屬性指定事件處理函數(注意大小寫)
  • React使用的是自定義(合成)事件, 而不是使用的原生DOM事件-------為了更好的兼容性
  • React中的事件是通過事件委托方式處理的(委托給組件最外層的元素)--------為了高效

通過event.target得到發生事件的DOM元素對象------不要過度使用ref

<script type="text/babel">
    //  創建一個組件 
    class Demo extends React.Component {
      showInfo = () => {
        alert(this.myRef.current.value)
      }
      showData = (event) => {
        // 傳入的event是發生onBlur事件的事件源,也就是失去焦點提示數據的input框,
        // 通過event.target.value拿到input中的值
        alert(event.target.value)
      }
      render() {
        return (
          <div>
            <input ref={this.myRef = React.createRef()} type="text" placeholder="點擊按鈕提示數據" />&nbsp;
            <button onClick={this.showInfo}>點我提示左側數據</button>&nbsp;
            <input onBlur={this.showData} type="text" placeholder="失去焦點提示數據" />
          </div>
        )
      }
    }

    // 渲染組件到頁面
    ReactDOM.render(<Demo />, document.getElementById('test'))
  </script>

1.5 收集表單數據

1.5.1 理解

包含表單的組件分類

  • 受控組件
  • 非受控組件

1.5.2 案例

需求: 定義一個包含表單的組件

輸入用戶名密碼后, 點擊登錄提示輸入信息

效果如下:

Ⅰ.非受控組件

對input(以及頁面中其他的一些輸入型DOM)中輸入的數據現用現取,就是非受控組件

<script type="text/babel">
    // 創建一個組件
    class Login extends React.Component {
      // handleSubmit函數中直接取出input中輸入的數據(現用現取)
      handleSubmit = (event) => {
        event.preventDefault()     //阻止表單提交
        const { username, password } = this
        alert(`你輸入的用戶名是: ${username.value}, 你輸入的密碼是: ${password.value}`)
      }
      render() {
        return (
          // 對input(以及其他的一些輸入型DOM)中輸入的數據現用現取,就是非受控組件
          <form onSubmit={this.handleSubmit}>
            用戶名:<input ref={(c) => { this.username = c }} type="text" name="username" />
            密碼:<input ref={(c) => { this.password = c }} type="password" name="password" />
            {/* form中的button默認提交,點擊后觸發表單提交事件onSubmit */}
            <button>登錄</button>
          </form>
        )
      }
    }
    // 渲染組件到頁面
    ReactDOM.render(<Login />, document.getElementById('test'))
  </script>

Ⅱ.受控組件

頁面中所有輸入類的DOM(input框),隨著用戶的輸入,能把輸入的東西維護到狀態里(state),等需要用時,直接從狀態里面取出來,就是受控組件。(類似于vue里的雙向綁定

<script type="text/babel">
    // 創建一個組件
    class Login extends React.Component {
      // 初始化狀態
      state = { username: '', password: '' }

      // 保存用戶名到狀態中
      saveUsername = (event) => {
        this.setState({ username: event.target.value })
      }

      // 保存密碼到狀態中
      savePassword = (event) => {
        this.setState({ password: event.target.value })
      }

      // 表單提交的回調
      handleSubmit = (event) => {
        event.preventDefault()     //阻止表單提交
        const { username, password } = this.state
        alert(`你輸入的用戶名是: ${username}, 你輸入的密碼是: ${password}`)
      }

      /* 
      受控組件:(能夠省略ref)
      頁面中所有輸入類的DOM(input框),隨著用戶的輸入,能把輸入的東西維護到狀態里(state),等需要用時,直接從狀態里面取出來

      數據被onChange函數監聽,只要輸入型DOM數據一改變就觸發onChange中指定的回調函數
      回調函數saveUsername和savePassword中對改變的數據進行保存,保存到state中,需要使用的時候才取出。
      */
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            用戶名:<input onChange={this.saveUsername} type="text" name="username" />
            密碼:<input onChange={this.savePassword} type="password" name="password" />
            <button>登錄</button>
          </form>
        )
      }
    }
    // 渲染組件到頁面
    ReactDOM.render(<Login />, document.getElementById('test'))
  </script>

原文鏈接:https://blog.csdn.net/xuxuii/article/details/124989080

欄目分類
最近更新