React 受控表单

590 阅读6分钟

1. React中获取DOM元素

1.1 类组件中获取DOM元素

【 createRef 】 
import Reatc,{Component,createRef} from 'react'

class App extends Components{
  constructor() {
      super();
      this.myRef = createRef() 【 不引入createRef去情况】
      this.myRef = React.createRef() 【 引入createRef去情况 】

  }
  render() {
    return (
    	<div onClick={this.handole} ref={this.myRef}>获取DOM元素</div>
    )
  }
  handole =()=>{
  	const text = this.myRef.current 【 操作元素的内容 】
    console.log(text)
  }
}

1.2 函数组件中获取DOM元素

【 useRef 】

import useRef from 'react'

function App() {
	const myRef = useRef(null)
  
  const hanole =() =>{
  	console.log(myRef.surrent)
  }
  return (
  	<button onClick={hanole}>
  		获取DOM元素
   	</button>
  )
}

1.3 ref的类型

  1. 当【ref】属性在组件上使用的时候,他的返回值也是不同的【类组件】,current的返回值是一个组件对象,可以通过组件对象,直接调用子组件内部的方法,去操作一些值等等
import React,{Component} from 'react'

export default class Header extends Component{ 【子】
  render() {
    return (
    	<div>子组件</div>
    )
  }
  handole = () =>{
  	console.log('父组件调用我了')
  }
}

export default class App extends Component { 【父】
  constructor() {
      super();
      this.myRef = React.createRef()

  }
  render() {
    return (
      <div>
        <Header  ref={myRef}/>
        <button onClick={this.getChildern}>调用子组件中的方法</button>
      </div>
    )
  }
  getChildern = () =>{
  	console.log(this.myRef.current.handole) 【 current返回的是一个组件对象,通过组件对象调用方法 】
  }
}
  1. 如果当前使用ref的组件是一个函数组件,是获取不到组件对象的,

1.4 ref在函数组件中使用(高阶组件) 待更新

2. 受控表单与非受控表单

  1. 【受控表单】,在react中推荐去使用受控表单,表单元素的值被react进行管理,将表单的内容存在【state】里面, 并且表单元素中的值,是在state里面进行获取的
  2. 【非受控表单】,表单元素数据由自身进行管理,表单元素的值存放在dom上,获取的时候需要操作Dom元素

2.1 受控表单

2.1.1 input输入框

1. 单向的去绑定数据 】
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
  render() {
    <form>
    	<input value={this.state.name} />
    </form>
  }
}
【 单向的数据绑定,输入框了里面的值是不可以被更改的,想要更改,就要使用【 onChange 】事件 】
export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
	render() {
  	<form>
    	<input value={this.state.name} onChange={this.handole.bind(this,e)} />
    </form>
  }
	handole = (e) => {
  	this.setState({
    	name: e.target.value
    })
  }
}
【 在使用onChange的时候,是需要传递事件对象的,通过事件对象拿到输入框输入的内容,重新覆盖state里面的值 】

2.1.2 多个Input的处理

  1. 在一个组件里面,有时候会有很多个输入框,开发的时候,不可能每一个输入框都写一个方法,这些方法操作都是相同的,就需要合并方法,合并成一个方法,通过动态设置【对象的key值,在给每一个输入框设置name属性值】,具体实现如下
1. 首先要给输入框设置name值 】
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	user: '',
    password: '',
    email: ''
  }
  render() {
    <form>
      <input 
        value={this.state.user}
        name="user"
        onChange={this.handole.bind(this.e)}  />
      <input 
        value={this.state.password}
        name="password"
        onChange={this.handole.bind(this.e)} />
      <input 
        value={this.state.email}
        name="email"
        onChange={this.handole.bind(this.e)} />
    </form>
  }
	handole = (e) =>{ 【 通过事件对象,拿到每一个元素身上的name,与value,分别进行赋值 】
  	this.setState({ 【 在操作的时候,必须input的name值要与state的key值相同 】
    	[e.target.name]:e.target.valur
    })
  }
}
【 2. 方式二,在元素身上直接设置 】
export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
  render() {
    <form>
      <input
        value={this.state.name}
        onChange={e => {this.setState({ name: e.target.name })} } />
    </form>
  }
}

2.1.3 form默认提交

  1. form表单默认会提交表单,需要进行阻止,需要提交表单的时候,通过手动提交表单
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
  render() {
         【 侦听onSubmit事件,传递事件对象,通过事件对象取消默认行为 】
    <form onSubmit={ (e) =>{this.handoleSubmit(e)} }> 
      <input value={this.state.name} />
      <input type="submit" />
    </form>
  }
  handoleSubmit = (e) =>{
  	e.preventDefault(); 【阻止默认行为】
  }
}

2.1.4 input细节处理

Warning: You provided a `value` prop to a form field without an `onChange` handler. 
This will render a read-only field. If the field should be mutable use `defaultValue`.
Otherwise, set either `onChange` or `readOnly`.
  1. 上面的警告,在react中,如果只是用表单展示数据,并没有修改以及其他操作,控制台就会警告,在react中,如果不设置【onChange】,react会认为这里的输入框是展示,不进行操作,他就会检测其他,发现什么都没有设置,就会在控制台警告
【 解决Warningimport React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
  render() {
    <form>
      【 解决方式一: readOnly 】情景,想要展示state里面的值,但是不想交给react进行管理
      <input value={this.state.name} readOnly/>
      
      【 解决方式二:defaultValue 】情景,input指向去展示state里的数据,也就是只读不能写
      <input defaultValue={this.state.name} />
    </form>
  }
}

2.1.5 下拉表单

import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: 'react' 【 值要与value值是相同的 】
  }
   render() {
    <select value={this.state.name} onChange={(e} =>{this.setState({ name: e.target.value })}>
      <option value="react">react</option>   	
      <option value="vue">vue</option>
      <option value="ag">ag</option>
    </select>
  }
}

2.1.6 单选与复选

  1. 【受控单选】
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	sex: '男'
  }
   render() {
    <form>
      【 默认第一个值是被选中的,在react中提供了defaultChecked,返回值是布尔值,为true被选中 】
      【 defaultChecked需要动态的设置,后期会做切换,所以这里的值要被设置成动态的值,
      	 通过修改值的方式,去动态的切换单选按钮 】
       <input type="radio" name="sex" value="男" defaultChecked={this.state.sex == '男'} />男
      【 后期会通过修改state里面的默认值,实现动态切换 】
      <input type="radio" name="sex" value="女" defaultChecked={this.state.sex == '女'} /></form>
  }
}
  1. 【受控复选】
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '表单内容'
  }
	student = [ // 模拟后端返回复选框的数据
  	{
      id: 0,
      name: 'vue',
      isChecked: true
    },
    {
      id: 2,
      name: 'react',
      isChecked: false
    },
    {
      id: 3,
      name: 'angle',
      isChecked: false
    }
  ]
  render() {
    <form onSubmit={e=>this.submit(e)}>
      {
      	this.student.map((item,index) => {
          return (
            <label key={item.id} htmlFor="FormChec">
            <input 
                className="FormChec"
                type="checkbox"
                defaultChecked={item.isChecked}
                onChange={(e) => {this.handole(index,e)}} 【 修改状态值 】
               />{item.name}
            </label>
          )
        })
      }
    </form>
  }
	handole = (index,e) => { 【 修改状态值 】
  	this.student[index].isChecked = e.target.checked
  }
  submit =(ev)=>{ 【 提交表单 】
  	ev.preventDefault();
    【 点击提交按钮,需要拿到想要的数据,使用变量进行存储 】
    let prop = this.student.filter(item => item.isChecked).map(item => item.id)
    【 将提取出来的数据与之前的state内部的数据进行合并,最终处理的结果返回到服务器使用 】
    prop = {
      ...this.state,prop
    }
  }
}

2.2 非受控表单 待更新

3. 单向数据流

  1. 单项数据流的设计原则是要求我们将不同组件之间需要共享的数据都定义在最上层,父组件内部,组件之间存在着嵌套关系,一层套一层组件。
import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '共享数据'
  }
	render() {
		return (
    	<div>
      	<Header { ...this.state }/>
      </div>
    )
  }
}

export default function Header(props) { 【props接收上层组件传递数据】
	return (
  	<div>
    	<Main {...props}/>
    </div>
  )
}
export default function Main(props) { 【props接收上层组件传递数据】
	return (
  	<div>
    	<span>{ props.name }</span>
    </div>
  )
}

3.1 如何修改单项数据流

  1. 单项数据流修改,不仅仅是将数据传递给子组件,有时候,子组件触发操作,去更改顶层数据。子组件通过调用父组件传递过来的方法,可以更改数据。
1. 通过父组件定义修改state的方法,将方法传递给组件,组件接收事件,调用,并且传递想要修改的值 】

import React,{Component} from 'react'

export derault class App extends Component {
	state = {
  	name: '共享数据'
  }
   render() {
     return (
    	<div>
      	<Header { ...this.state }/>
      </div>
    )
  }
	handole =(value)=>{ 【 接收组件传递的值 】
  	this.setState({
    	name: value.name
    })
  }
}

export default function Main(props) { 【最底层组件去修改顶层组件的数据】
	return (
  	<div>
    	<span>{ props.name }</span>
      <button onClick={() =>{props.handole({name:'底层组件修改了顶层组件的数据'})}}>修改顶层数据</button>
    </div>
  )
}

3.2 单项数据流的特性

  1. 数据流动原则:从顶层父组件,将数据传递给子组件。

  2. 使用单项数据流时,需要将共享的数据定义在顶层父组件内部

  3. 子组件通过调用父组件传递过来的方法,可以更改数据。

  4. 当数据发生更改后,重新将数据渲染到DOM元素上