1. 程式人生 > 其它 >react學習——受控元件及非受控元件及ref獲取dom節點

react學習——受控元件及非受控元件及ref獲取dom節點

技術標籤:reactreactjs

react 建立專案的兩種方式

  • 1.npm 全域性安裝
npm install -g create-react-app
create-react-app my-react-app

一般安裝到了你的npm資料夾下
設定在系統的環境變數裡面

  • 2.npx 非全域性安裝
// 現將 my-react-app下載到本地,用完刪除
npx create-react-app my-react-app

受控表單(受控元件)

什麼是表單??

  • 在React裡,HTML表單元素的工作方式和其他的DOM元素有些不同,這是因為表單元素會保持一些內部的state.
  • 例如這個純 HTML 表單只接受一個名稱:
<form>
  <label>
    名字:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="提交" />
</form>
  • 此表單具有預設的 HTML 表單行為,即在使用者提交表單後瀏覽到新頁面。
  • 如果你在 React 中執行相同的程式碼,它依然有效。
  • 但大多數情況下,使用 JavaScript 函式可以很方便的處理表單的提交, 同時還可以訪問使用者填寫的表單資料。實現這種效果的標準方式是使用“受控元件”

什麼是受控元件?

  • 在 HTML 中,表單元素(如<input><textarea><select>)通常自己維護 state,並根據使用者輸入進行更新。
  • 而在 React 中,可變狀態(mutable state)通常儲存在元件的 state 屬性中,並且只能通過使用setState()來更新。

input受控:

例1:如果我們想讓前一個示例在提交時打印出名稱

  • 我們可以將表單寫為受控元件:
import React, { Component } from 'react'
// 如何獲取表單資料?????
// 獲取值/存值

// 受控表單
// 可以設定預設值
// defaultValue 
export default class App extends Component { state={ username:"", } handleClick=(params) => { // console.log(this.username); console.log(this.state.username); } handleChange=(e) => { // 預設傳一個事件源 // 傳參之後事件源跑哪裡去了?作為裡面的第二個引數傳入 // 1-獲取到表單中的值 let username = e.target.value console.log(username); // 2-存值 // 2-1.放物件裡 this.username = e.target.value // this.username = e.target.value // 2-2.放狀態裡 this.username = e.target.value this.setState({ username:e.target.value }) // 為什麼第二種好?? // 輸入框本來是自己控制的 // 怎麼設定成受我們控制,而不受瀏覽器控制 // 受控表單有初始value時,再輸入就不受瀏覽器控制了 // 所以想要更新介面的話。就要使用改變狀態的方式了,成為受我們控制的表單 } render() { return ( <div> {/* 登入框的例子 */} <label htmlFor="username"> 使用者名稱: <input type="text" id="username" value={this.state.username} onChange={this.handleChange}/> </label> <br></br> <label htmlFor="password"> 密碼: <input type="password" id="password"/> </label> <br></br> <button onClick={this.handleClick}>提交</button> </div> ) } }
  • 由於在表單元素上設定了 value 屬性,因此顯示的值將始終為 this.state.value,這使得 React 的 state 成為唯一資料來源。
  • 由於 handlechange 在每次按鍵時都會執行並更新 React 的 state,因此顯示的值將隨著使用者輸入而更新。
  • 對於受控元件來說,輸入的值始終由 React 的 state 驅動。

例2:合併多個輸入

  • 當需要處理多個input元素時,我們可以給每個元素新增name屬性,並讓處理函式根據event.target.name的值選擇要執行的操作。
  • 下面的是使用data屬性,其實原理是一樣的。
  • 還想獲取密碼,需要在密碼框中再定義一個相似的onChange事件,所以想把這兩個相似的事件合併成一個事件就解決,獲取不同輸入框的不同的value值,
  • 這裡使用了data屬性,命名成了data-name
import React, { Component } from "react";
// 合併多個輸入
export default class App extends Component {
  state = {
    username: "",
    password: "",
  };
  handleClick = (params) => {
    console.log(this.state.username, this.state.password);
  };
  // handleChange = (e) => {
  //   this.setState({
  //     username: e.target.value,
  //   });
  // };
  // 原來的密碼框事件是叫這個handlePasswordChange
  // handlePasswordChange = (e) => {
  //   this.setState({
  //     password: e.target.value,
  //   });
  // };
  // 兩個函式合併成一個
  // 傳參 合併多個輸入
  // e.target.dataset.name
  handleChange = (e) => {
    this.setState({
      [e.target.dataset.name]: e.target.value,
    });
  };
  render() {
    return (
      <div>
        <label htmlFor="username">
          使用者名稱:{" "}
          <input
            type="text"
            id="username"
            data-name="username"
            value={this.state.username}
            onChange={this.handleChange}
          />
        </label>
        <br></br>
        <label htmlFor="password">
          密碼:{" "}
          <input
            type="password"
            id="password"
            data-name="password"
            value={this.state.password}
            onChange={this.handleChange}
          />
        </label>
        <br></br>
        <button onClick={this.handleClick}>提交</button>
      </div>
    );
  }
}

select受控:

  • 在HTML中
<select>
  <option value="grapefruit">葡萄柚</option>
  <option value="lime">酸橙</option>
  <option selected value="coconut">椰子</option>
  <option value="mango">芒果</option>
</select>
  • 請注意,由於 selected 屬性的緣故,椰子選項預設被選中。
  • React 並不會使用 selected 屬性,而是在根 select 標籤上使用 value 屬性。這在受控元件中更便捷,因為您只需要在根標籤中更新它。
  • 例如:
import React, { Component } from 'react'
// select表單
// 怎麼變為 受控表單
export default class App extends Component {
  // 呼叫父類的初始化的方法
  constructor(props){
    super(props)
    this.state={
      selectValue:"中文",
    }
  }
  handleChange=(e) => {
    this.setState({
      selectValue:e.target.value
    })
  }
  render() {
    return (
      <div>
        <select name="" id="" value={this.state.selectValue} onChange={this.handleChange}>
          <option value="粵語">粵語</option>
          <option value="德語">德語</option>
          <option value="中文">中文</option>
        </select>
      </div>
    )
  }
}
  • 總的來說,這使得, <input type="text">, <textarea><select>之類的標籤都非常相似—它們都接受一個 value 屬性,你可以使用它來實現受控元件。

受控輸入空值時!

非受控元件

檔案 input 標籤

  • 在 HTML 中,<input type="file"> 允許使用者從儲存裝置中選擇一個或多個檔案,將其上傳到伺服器,或通過使用 JavaScript 的 File API 進行控制。
  • 因為它的 value 只讀,所以它是 React 中的一個非受控元件。
<input type="file" />
  • 在react中,執行下面的程式碼,會報錯
import React, { Component } from "react";
export default class App extends Component {
  state = {
    value:"",
  };
  componentDidMount() {
    document.getElementById("file").addEventListener("change", function (e) {
      // 獲取到上傳檔案的內容
      console.log(e.target.files);
    });
  }
  render() {
    return (
      <div>
        <input type="file" name="" id="file" value={this.state.value} />
      </div>
    );
  }
}

  • 在這裡插入圖片描述
  • 非受控表單

ref獲取dom節點

例子1:

import React, { Component } from "react";
export default class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    // 1- 建立了一個 ref
    this.fileref = React.createRef();
  }
  componentDidMount() {
    document.getElementById("file").addEventListener("change", function (e) {
      // 獲取到上傳檔案的內容
      console.log(e.target.files);
    });
  }
  handleClick = (e) => {
    console.log(this.fileref.current.value);
  };
  render() {
    return (
      <div>
        <input type="file" name="" id="file" ref={this.fileref}/>
        <button onClick={this.handleClick}>獲取dom節點</button>
      </div>
    );
  }
}

例子2:輸入框自動聚焦

import React, { Component } from 'react'
// 輸入框自動聚焦
// 在掛載的時候,ref獲取節點,給他onFous
export default class App extends Component {
  constructor(props){
    super(props)
    this.inputRef = React.createRef()
  }
  componentDidMount() {
      // document.getElementById("text").focus()
      this.inputRef.current.focus()
  }
  render() {
    return (
      <div>
        <input type="text" id="text" ref={this.inputRef}/>
      </div>
    )
  }
}
  • 因為非受控元件將真實資料儲存在 DOM 節點中,所以在使用非受控元件時,有時候反而更容易同時整合 React 和非 React 程式碼。如果你不介意程式碼美觀性,並且希望快速編寫程式碼,使用非受控元件往往可以減少你的程式碼量。否則,你應該使用受控元件。