react學習——受控元件及非受控元件及ref獲取dom節點
阿新 • • 發佈:2021-01-16
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 程式碼。如果你不介意程式碼美觀性,並且希望快速編寫程式碼,使用非受控元件往往可以減少你的程式碼量。否則,你應該使用受控元件。