React受控組件與非受控組件詳細(xì)介紹
1. 受控組件
1.1 介紹
概述:
將 state 與表單項(xiàng)中的 value 值綁定在一起,有 state 的值來控制表單元素的值,稱為受控組件。
綁定步驟:
- 在state中添加一個(gè)狀態(tài),作為表單元素的value值
- 給表單元素綁定 change 事件,將表單元素的值設(shè)置為 state 的值
語法:
# value={this.state.xx} 事件onChange=“方法,修改state中的數(shù)據(jù)” <input type="text" value={this.state.username} onChange={this.inputChange.bind(this)} /> 注:多表單元素需優(yōu)化事件方法 this.setState({ [e.target.name]: e.target.value })
使用:
import React, { Component } from 'react'; class App extends Component { state = { username: '', password: '' } setValue = name => evt => { this.setState({ // 變量的值當(dāng)前對象的key,寫法 [name]: evt.target.value.trim() }) } login = () => { console.log(this.state); } render() { let { username, password } = this.state return ( <div> <div> {/* 表單項(xiàng)中的value值,通過state中的屬性值來賦值的,叫受控組件 受控組件: value={this.state.xx} 事件onChange=“方法,修改state中的數(shù)據(jù)” */} <input type="text" value={username} onChange={this.setValue('username')} /> </div> <div> <input type="text" value={password} onChange={this.setValue('password')} /> </div> <div> <button onClick={this.login}>登錄一下</button> </div> </div> ); } } export default App;
1.2 受控組件簡寫
同樣是實(shí)現(xiàn)上面案例中的場景,我們還可以有簡寫方式。
loginForm.js:
export default _this => ({ username: { value: '', onChange: e => _this.setState(state => ({ username: { ...state.username, value: e.target.value } })) }, password: { value: '', onChange: e => _this.setState(state => ({ password: { ...state.password, value: e.target.value } })) } })
App.jsx:
import React, { Component } from 'react'; import loginForm from './form/loginForm'; class App extends Component { state = { ...loginForm(this), num: 100 } login = () => { console.log(this.state); } render() { let { username, password } = this.state return ( <div> <div> {/* 相當(dāng)于 value={username} onChange={this.setValue('username')} */} <input type="text" {...username} /> </div> <div> <input type="text" {...password} /> </div> <div> <button onClick={this.login}>登錄一下</button> </div> </div> ); } } export default App;
1.3 在表單中使用受控組件
import React, { Component } from 'react'; class App extends Component { state = { username: '', sex: '女', isshow: true, lessons: ['html', 'js'] } setLessonsFn = e => { if (e.target.checked) { this.setState(state => ({ lessons: [...state.lessons, e.target.value] })) } else { this.setState(state => ({ lessons: state.lessons.filter(item => item != e.target.value) })) } } login = () => { console.log(this.state); } render() { let { username, sex, isshow,lessons } = this.state return ( <div> <div> <input type="text" value={username} onChange={e => this.setState({ username: e.target.value })} /> </div> <div> {/* 單選 */} <input type="radio" name='sex' checked={sex === '男'} value='男' onChange={e => this.setState({ sex: e.target.value })} />男 <input type="radio" name='sex' checked={sex === '女'} value='女' onChange={e => this.setState({ sex: e.target.value })} />女 </div> <div> {/* 單個(gè)復(fù)選框 */} <input type="checkbox" checked={isshow} onChange={e => this.setState({ isshow: e.target.checked })} /> 顯示與隱藏 </div> <div> {/* 多個(gè)復(fù)選框 */} <div> <input type="checkbox" value='html' checked={lessons.includes('html')} onChange={this.setLessonsFn} />html <input type="checkbox" value='css' checked={lessons.includes('css')} onChange={this.setLessonsFn} />css <input type="checkbox" value='js' checked={lessons.includes('js')} onChange={this.setLessonsFn} />js </div> </div> <div> <button onClick={this.login}>登錄一下</button> </div> </div> ); } } export default App;
1.4 綜合案例
全選與反選,顯示與隱藏的應(yīng)用
描述:
本案例中我們將要實(shí)現(xiàn),對用戶名和密碼進(jìn)行正則驗(yàn)證(賬號只能是郵箱或手機(jī)號,別的不行;密碼必須是3位以上且有數(shù)字和字母 ),驗(yàn)證成功后點(diǎn)擊登錄下方顯示用戶列表。用戶列表有刪除功能,有全選和取消全選功能。選中所有的子項(xiàng),全選就自動(dòng)勾選,有一個(gè)子項(xiàng)沒選中,全選就取消勾選 。
實(shí)現(xiàn):
App.jsx:
import React, { Component } from 'react'; import UserTable from './components/UserTable'; class App extends Component { state = { username: '', password: '', show: false, } // 通過onChange事件來修改state中對應(yīng)屬性變化 setUsername = evt => { // console.log(evt.target.value.trim()); this.setState({ username: evt.target.value.trim() }) } setPassword = evt => { this.setState({ password: evt.target.value.trim() }) } setValue = name => evt => { this.setState({ // 變量的值當(dāng)前對象的key,寫法 [name]: evt.target.value.trim() }) } submit = () => { if (this.regExpValue(this.state.username, "username") && this.regExpValue(this.state.password, "password")) { alert("登錄成功!") this.login() } else { alert("正則驗(yàn)證失敗,請重新輸入!") } } regExpValue = (value, key) => { if (key === "username") { return /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(value) || /^1[3-9][0-9]{9}$/.test(value); } else { return /(?=.*?[A-Za-z])(?=.*?[0-9]).{3,}/.test(value); } } login = () => { // this.setState.show=true this.setState({ show: true }); console.log(this.state.show); } render() { let { username, password, show } = this.state return ( <div> <div> {/* 表單項(xiàng)中的value值,通過state中的屬性值來賦值的,叫受控組件 受控組件: value={this.state.xx} 事件onChange=“方法,修改state中的數(shù)據(jù)” */} <input type="text" value={username} onChange={this.setValue('username')} /> </div> <div> <input type="text" value={password} onChange={this.setValue('password')} /> </div> <div> <button onClick={this.submit}>登錄一下</button> </div> { this.state.show ? <UserTable /> : <div>不顯示</div> } </div> ); } } export default App;
UserTable.jsx:
import { getElementError } from '@testing-library/react'; import React, { Component } from 'react'; class UserTable extends Component { state = { users: [ { id: 1, name: '張三' }, { id: 2, name: '李四' }, { id: 3, name: '王五' }, { id: 4, name: '趙六' }, ], isshow: true, uids: [], tip: '全選', } all = e => { e.target.checked ? this.setState(state => ({ uids: state.users.map(({ id }) => id), tip: '取消全選' })) : this.setState({ uids: [], tip: '全選' }) console.log(this.state.uids); } select = tid => e => { let all = document.querySelector(".all"); if (e.target.checked) { setTimeout(() => { this.setState(state => ({ uids: [...state.uids, tid] })) if (this.state.uids.length === 4) all.checked = true }, 0); } else { setTimeout(() => { this.setState(state => ({ uids: state.uids.filter(item => item != tid) })) all.checked = false console.log(this.state.uids); }, 0); } } del = tid => () => { this.setState(state => ({ users: state.users.filter(({ id }) => id !== tid) })) } render() { let { users, uids, tip } = this.state return ( <div> <input type="checkbox" onChange={this.all} className="all" />{tip} <hr /> <ul> { users.map(({ id, name }) => ( <li key={id}> <span> <input type="checkbox" checked={uids.includes(id)} onChange={this.select(id)} /> </span> <span>{name} -- {id}</span> <span onClick={this.del(id)}>刪除</span> </li> )) } </ul> </div> ); } } export default UserTable;
2. 非受控組件介紹
概述:
表單項(xiàng)中的 value 或 checked 值,它不受 state 中的屬性控制,但是可以而是借助 ref,通過 dom 對象來獲取當(dāng)前表單項(xiàng)中的 value 或 checked 值,這就是非受控組件。
非受控組件的應(yīng)用的次數(shù)沒有受控組件多,在工作中,多數(shù)使用為受控組件。
注意:react 中如何來獲取普通的 html 元素的 dom 對象:ref 對象來獲取。
使用步驟:
- 調(diào)用 React.createRef() 方法創(chuàng)建ref對象
- 將創(chuàng)建好的 ref 對象添加到文本框中
- 通過ref對象獲取到文本框的值
語法:
class App extends React.Component { constructor(props){ super(props) //創(chuàng)建 ref this.username = React.createRef() } // 獲取文本框的值 fn =() => { console.log(this.username.current.value) } render(){ return ( <div> <input type ="text" ref={this.username} /> <button onClick ={this.fn}>獲取值</button> </div> ) } }
示例:
// createRef 通過此方法得到一個(gè)ref實(shí)例對象 // ref 如果綁定在普通的html元素中則返回dom對象 // ref 如果綁定在"類組件"中,則返回當(dāng)前自定義類組件實(shí)例對象,可以用它來完成組件通信 import React, { Component, createRef } from 'react' class App extends Component { // 創(chuàng)建得到一個(gè)ref實(shí)例對象 usernameRef = createRef() getUsernameInput = () => { // 通過ref綁定好的對象,來完成對應(yīng)表單項(xiàng)數(shù)據(jù)的獲取 console.log(this.usernameRef.current.value) } render() { return ( <div> <input type="text" ref={this.usernameRef} /> <button onClick={this.getUsernameInput}>獲取表單項(xiàng)中的數(shù)據(jù)</button> </div> ) } } export default App
注意:
- createRef:通過此方法可以得到一個(gè) ref 實(shí)例對象
- ref 如果綁定在普通的html元素中則返回dom對象
- ref 如果綁定在"類組件"中,則返回當(dāng)前自定義類組件實(shí)例對象,可以用它來完成組件通信
非受控組件的應(yīng)用
import React, { Component, createRef } from 'react' class App extends Component { // 創(chuàng)建得到一個(gè)ref實(shí)例對象 usernameRef = createRef() isShowRef = createRef() // 等同于:lessonsRefs = [createRef(), createRef(), createRef()] lessonsRefs = Array(3) .fill('') .map(_ => createRef()) getUsernameInput = evt => { // 通過dom向上查找,不推薦,層級不確定,有時(shí)候會找不到 // console.dir(evt.target.previousSibling.value) // 通過ref綁定好的對象,來完成對應(yīng)表單項(xiàng)數(shù)據(jù)的獲取 console.log(this.usernameRef.current.value) if (this.isShowRef.current.checked) { console.log(this.isShowRef.current.value) } console.log( this.lessonsRefs .map(item => { if (item.current.checked) { return item.current.value } else { return null } }) .filter(item => item != null) ) } render() { return ( <div> <input type="text" ref={this.usernameRef} /> <br /> <input type="checkbox" value="aaa" ref={this.isShowRef} />aaa <br /> <input type="checkbox" value="html" ref={this.lessonsRefs[0]} />html <input type="checkbox" value="css" ref={this.lessonsRefs[1]} />css <input type="checkbox" value="js" ref={this.lessonsRefs[2]} />js <button onClick={this.getUsernameInput}>獲取表單項(xiàng)中的數(shù)據(jù)</button> </div> ) } } export default App
注意:
獲取表單數(shù)據(jù)可以有兩種方案
通過 dom 向上查找,這種方案不推薦,因?yàn)?dom 層級不確定,有時(shí)候會找不到數(shù)據(jù)
console.dir(evt.target.previousSibling.value)
通過ref綁定好的對象,來完成對應(yīng)表單項(xiàng)數(shù)據(jù)的獲取\
console.log(this.usernameRef.current.value)
到此這篇關(guān)于React受控組件與非受控組件詳細(xì)介紹的文章就介紹到這了,更多相關(guān)React受控組件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React組件實(shí)例三大核心屬性State props Refs詳解
組件實(shí)例的三大核心屬性是:State、Props、Refs。類組件中這三大屬性都存在。函數(shù)式組件中訪問不到 this,也就不存在組件實(shí)例這種說法,但由于它的特殊性(函數(shù)可以接收參數(shù)),所以存在Props這種屬性2022-12-12React實(shí)現(xiàn)頁面狀態(tài)緩存(keep-alive)的示例代碼
因?yàn)?react、vue都是單頁面應(yīng)用,路由跳轉(zhuǎn)時(shí),就會銷毀上一個(gè)頁面的組件,但是有些項(xiàng)目不想被銷毀,想保存狀態(tài),本文給大家介紹了React實(shí)現(xiàn)頁面狀態(tài)緩存(keep-alive)的代碼示例,需要的朋友可以參考下2024-01-01Redux?Toolkit的基本使用示例詳解(Redux工具包)
這篇文章主要介紹了Redux?Toolkit的基本使用,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-12-12react ant protable自定義實(shí)現(xiàn)搜索下拉框
這篇文章主要介紹了react ant protable自定義實(shí)現(xiàn)搜索下拉框,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06react中路由跳轉(zhuǎn)及傳參的實(shí)現(xiàn)
本文主要介紹了react中路由跳轉(zhuǎn)及傳參的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05react hook使用useState更新數(shù)組,無法更新問題及解決
這篇文章主要介紹了react hook使用useState更新數(shù)組,無法更新問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03關(guān)于React動(dòng)態(tài)加載路由處理的相關(guān)問題
這篇文章主要介紹了關(guān)于React動(dòng)態(tài)加載路由處理的相關(guān)問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01