React高级特性之受控和非受控组件

一、受控组件

受控组件:input框自己的状态被React组件状态控制

// 类组件引入React
import React from 'react'

class InputComponent extends React.Component{
  state = {
    message: 'zm66666'
  }
  changeHandler = (e) => {
    this.setState({
      message: e.target.value
    })
  }
  render () {
    // 使用状态
    return (
      <div>
        {/* 绑定value 绑定事件 */}
        <input type='text' value={this.state.message} onChange={this.changeHandler} />
      </div>
    )
  }
}

function App () {
  return (
    <div className="App">
      <InputComponent/>
    </div>
  )
}

export default App


// 受控组件:input框自己的状态被React组件状态控制

// 1. 在组件的state中声明一个组件的状态数据
// 2. 将状态数据设置为input标签元素的value属性的值
// 3. 为input添加change事件,在事件处理程序中,通过事件对象e获取到当前文本框的值(即用户当前输入的值)
// 4. 调用setState方法,将文本框的值作为state状态的最新值
// 受控组件

import React, { FC, useState, ChangeEvent } from 'react'
// import type { ChangeEvent } from 'react'

const FormDemo: FC = () => {

  // input
  const [text, setText] = useState<string>('input')
  const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
    setText(event.target.value)
  }

  // textarea
  const [text2, setText2] = useState<string>('textarea')
  const handleChange2 = (event: ChangeEvent<HTMLTextAreaElement>) => {
    setText2(event.target.value)
  }
  const getHtml = () => {
    return { __html: text2.replaceAll('\n', '<br>') }
  }

  // radio
  const [gender, setGender] = useState<string>('male')
  const handleChange3 = (event: ChangeEvent<HTMLInputElement>) => {
    setGender(event.target.value)
  }

  // checkbox
  // const [checked, setChecked] = useState(false)
  // const handleChange4 = (event: ChangeEvent<HTMLInputElement>) => {
  //   setChecked(!checked)
  // }

  // checkbox组
  const [selectedFruitList, setselectedFruitList] = useState<string[]>([])
  const handleChange5 = (event: ChangeEvent<HTMLInputElement>) => {
    const fruit = event.target.value
    if (selectedFruitList.includes(fruit)) {
      setselectedFruitList(selectedFruitList.filter(f => {
        if (f === fruit) return false
        return true
      }))
    } else {
      setselectedFruitList(selectedFruitList.concat(fruit))
    }
  }

  // select
  const [lang, setLang] = useState<string>('js')
  const handleChange6 = (event: ChangeEvent<HTMLSelectElement>) => {
    setLang(event.target.value)
  }


  return (
    <>
      <div>
        FormDemo:
        <div>
          <span>input:</span>
          <input type="text" value={text} onChange={handleChange}/>
          <button onClick={() => console.log(text)}>打印</button>
          <button onClick={() => setText('66666666')}>set</button>
        </div>
        <div>
          <span>textarea:</span>
          <textarea value={text2} onChange={handleChange2}/>
          <p dangerouslySetInnerHTML={getHtml()}></p>
        </div>
        <div>
          <span>radio:</span>
          <label htmlFor="radio1"></label>
          <input type="radio" value='male' name='gender' id='radio1' onChange={handleChange3} checked={gender === 'male'}/>
          <label htmlFor="radio2"></label>
          <input type="radio" value='female' name='gender' id='radio2' onChange={handleChange3} checked={gender === 'female'}/>
          <button onClick={() => console.log(gender)}>打印{gender}</button>
        </div>
        {/* <div>
          <span>checkbox:</span> 
          <label htmlFor="checkbox1">选中</label>
          <input type="checkbox" id='checkbox' checked={checked} onChange={handleChange4}/>{checked.toString()}
        </div> */}
        <div>
          <span>checkbox组:</span> 
          <label htmlFor="checkbox1">苹果</label>
          <input type="checkbox" id='checkbox1' value='apple' checked={selectedFruitList.includes('apple')} onChange={handleChange5}/>
          <label htmlFor="checkbox2">橙子</label>
          <input type="checkbox" id='checkbox2' value='orange' checked={selectedFruitList.includes('orange')} onChange={handleChange5}/>
          <label htmlFor="checkbox3">香蕉</label>
          <input type="checkbox" id='checkbox3' value='banana' checked={selectedFruitList.includes('banana')} onChange={handleChange5}/>
          {JSON.stringify(selectedFruitList)}
        </div>
        <div>
          <span>select:</span>
          <select value={lang} onChange={handleChange6}>
            <option value='java'>java</option>
            <option value='js'>js</option>
            <option value='php'>php</option>
          </select>
        </div>
      </div>
    </>
  )
}


export default FormDemo

// 受控组件 vs 非受控组件
// 受控组件: 值同步到state, 使用value属性
// 非受控组件: 值不同步state, 使用defaultValue属性
// react推荐使用受控组件, 看似麻烦,但是 更加可控

二、非受控组件

// 类组件引入React createRef
import React, { createRef } from 'react'

class InputComponent extends React.Component{
  // 使用createRef产生一个存放dom的对象容器
  msgRef = createRef()

  changeHandler = () => {
    console.log(this.msgRef.current)
    console.log(this.msgRef.current.value)
  }

  render () {
    // 使用状态
    return (
      <div>
        {/* ref绑定 获取真实dom */}
        <input ref={this.msgRef} />
        <button onClick={this.changeHandler}>click</button>
      </div>
    )
  }
}

function App () {
  return (
    <div className="App">
      <InputComponent/>
    </div>
  )
}

export default App


// 非受控组件: 
// 通过手动操作dom的方式获取文本框的值
// 文本框的状态不受react组件的state中的状态控制
// 直接通过原生dom获取输入框的值

// 1.导入createRef 函数
// 2.调用createRef函数,创建一个ref对象,存储到名为msgRef的实例属性中
// 3.为input添加ref属性,值为msgRef
// 4.在按钮的事件处理程序中,通过msgRef.current即可拿到input对应的dom元素,
// 而其中msgRef.current.value拿到的就是文本框的值
import React from 'react'

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            name: '双越',
            flag: true,
        }
        this.nameInputRef = React.createRef() // 创建 ref
        this.fileInputRef = React.createRef()
    }
    render() {
        // // input defaultValue
        // return <div>
        //     {/* 使用 defaultValue 而不是 value ,使用 ref */}
        //     <input defaultValue={this.state.name} ref={this.nameInputRef}/>
        //     {/* state 并不会随着改变 */}
        //     <span>state.name: {this.state.name}</span>
        //     <br/>
        //     <button onClick={this.alertName}>alert name</button>
        // </div>

        // // checkbox defaultChecked
        // return <div>
        //     <input
        //         type="checkbox"
        //         defaultChecked={this.state.flag}
        //     />
        // </div>

        // file
        return <div>
            <input type="file" ref={this.fileInputRef}/> // 获取上传问卷 要使用非受控组件!!!!!!!!
            <button onClick={this.alertFile}>alert file</button>
        </div>

    }
    alertName = () => {
        const elem = this.nameInputRef.current // 通过 ref 获取 DOM 节点
        alert(elem.value) // 不是 this.state.name
    }
    alertFile = () => {
        const elem = this.fileInputRef.current // 通过 ref 获取 DOM 节点
        alert(elem.files[0].name)
    }
}

export default App

三、总结

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老电影故事

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值