目录
模拟:复杂(真实)受控组件表单(form里面有多种数据输入)
方式一:ref="key" 原理:this.refs={} => this.refs={key:真实DOM}
方式二:ref={e=>this.key=e} =>直接赋值this.key=真实DOM
方式三:直接调用react提供的方法createRef();this.key=React.createRef()
1.组件form
受控组件及其特点
组件受状态和属性变化控制,称为受控组件。
特点:数据驱动,组件不直接操作DOM,而是由ReactDOM自动同步
非受控组件及其特点
组件不受状态和属性变化控制,称为非受控组件。
特点:可以直接操作DOM,类似于传统的html表单操作,通过ref获取真实DOM。
模拟:简单受控组件表单
(数据传递) =>数据源state+属性绑定value+事件监听onChange
class App extends React.Component{
state = {name:"",age:18}
handleClick = () ={
console.log("form data:",this.state)
}
handleChange = (e) ={
console.log(e.target.value) //获取到input输入内容
this.setState({
name:e.target.value
})
}
input两个方向绑定数据:
1.通过value,同步state=>input (属性绑定)
2.通过onChange,同步input输入输入内容=>state (事件绑定)
render(){
return(
<div>
name:
//受控组件收集表单
<input type:"text" value = {this.state.name} // input属性绑定
onChange={this.handleCHange}> //input事件绑定
<button onClick={this.handleClick}>commit 提交</button>
</div>
)
}
}
ReactDOM.render(<App />,document.getElementById("app"))
模拟:复杂(真实)受控组件表单(form里面有多种数据输入)
class App extends React.Component{
state = {
name:"user",
age:18,
single:false,
desc:"intoduction",
hobby:"playing"
}
handleSubmit=()={
//获取收集表单数据
console.log("form data:",this.state)
//提交数据
//阻止默认行为
e.preventDefault()
}
handleChange1 = (e) ={
this.setState({
name:e.target.value
})
}
handleChange2 = (e) ={
this.setState({
age:e.target.value
})
}
handleChange3 = (e) ={
console.log(e.target.checked) //点击,在true和false之间来回切换
//将表单中内容同步到数据中
this.setState({
single:e.target.checked
})
}
handleChange4 = (e) ={
this.setState({
desc.target.value
})
}
handleChange5 = (e) ={
this.setState({
hobby:e.target.value
})
}
render(){
return(
<form onSubmit = {this.handleSubmit}>
name:
<input type:"text" value = {this.state.name} // input属性绑定
onChange={this.handleChange1} /> //input事件绑定
age:
<input type:"number" value = {this.state.age}
onChange={this.handleChange2} />
single:
<input type:"checkbox" value = {this.state.single}
onChange={this.handleChange3} />
desc:
<textarea value = {this.state.desc}
onChange={this.handleChange4}/>
hobby:
<select name:"" value={this.state.hobby}
onChange={this.handleChange5}>
<option value:"eatting">吃</option>
<option value:"palying">玩</option>
<option value:"sleeping">睡</option>
</select>
<input type="submit" value="commit" />
</form>
)
}
}
ReactDOM.render(<App />,document.getElementById("app"))
注意:handleChange1~5 中代码重复率高。
this.setState({key:value}),key动态,value:r.target.value,注意:e.target.checked不同
降低代码重复写法降低代码重复写法
class App extends React.Component{
state = {
name:"user",
age:18,
single:false,
desc:"intoduction",
hobby:"playing"
}
handleSubmit=()={
//获取收集表单数据
console.log("form data:",this.state)
//提交数据
//阻止默认行为
e.preventDefault()
}
handleChange = (e) ={
console.dir(e.target)
let target = e.target
let key = target.name
//注意:checkedbox情况不同value = target.checked,追加判断
let type = target.type
let value = type==checkedbox?target.checked:target.value
this.setState({
[key]:value //动态追加key
})
}
render(){
return(
<form onSubmit = {this.handleSubmit}>
name:
<input type:"text" name="name"
value = {this.state.name}
onChange={this.handleChange} />
age:
<input type:"number" name="age"
value = {this.state.age}
onChange={this.handleChange} />
single:
<input type:"checkbox" name="single"
value = {this.state.single}
onChange={this.handleChange} />
desc:
<textarea name="desc"
value = {this.state.desc}
onChange={this.handleChange}/>
hobby:
<select name:"hobby" value={this.state.hobby}
onChange={this.handleChange}>
<option value:"eatting">吃</option>
<option value:"palying">玩</option>
<option value:"sleeping">睡</option>
</select>
<input type="submit" value="commit" />
</form>
)
}
}
ReactDOM.render(<App />,document.getElementById("app"))
模拟:非受控组件
受控组件形式自动时钟
class Clock extends React.Components{
state = {time:new Date().toLocalTimeString()}
render(){
return(
<div>
<h2>{this.state.time}</h2>
</div>
)
}
componentDidMount(){ //第一次挂载完毕生命周期的钩子函数自动执行
setInterval(()=>{
this.setState({
time:new Date().toLocalTimeString()
})
},1000)
}
}
ReactDOM.render(<Clock />,document.getElementById("app"))
非受控组件形式自动时钟
1.真实DOM容器ref-string类型实现
组件实例属性:this.ref = {},这个对象容器用来存储真实DOM的引用
class Clock extends React.Component{
render(){
return(
<div>
2.将真实DOM放在this.ref容器中
通过creatElement创建虚拟DOM,新增ref属性
通过ReactDOM.render同步渲染虚拟DOM=>真实DOM=>判断是否有ref属性
==>有ref:将ref属性对应的虚拟DOM转化成真实DOM=>放在this.ref={}容器中
[ 将ref属性对应的值作为key,将真实DOM作为value ]
<h2 ref="timeRef">{new Date().toLocalTimeString()}</h2>
//ref容器中存放:{timeRef:真实DOM<h2>}
</div>
)
}
componentDidMount(){ //已经渲染完毕,可以拿到真实DOM
console.log(this.refs)
setInterval(()=>{
3.this.ref中获取操作真实DOM=>给<h2>重新赋值
this.refs.timeRef.innerHTML = new Date().toLocaleTimeString()
},1000)
}
}
ReactDOM.render(<Clock />,document.getElementById("app"))
组件实例.refs = {key:真实DOM} ; key是ref属性对应的值
组件实例直接挂载key,组件实例.key=真实DOM => 自动化时钟
2.ref-函数类型实现
class Clock extends React.Component{
render(){
return(
<div>
2.将真实DOM放在this.ref容器中
通过creatElement创建虚拟DOM,新增ref属性
通过ReactDOM.render同步渲染虚拟DOM=>真实DOM=>判断是否有ref属性
==>有ref:ref属性对应的值是否是一个函数
==>是函数,直接执行这个函数,并将真实DOM作为参数传递。[组件实例.key=真实DOM]
<h2 ref = {e=>this.timeRef=e}>{new Dare().oLocaleTimeString()}</h2>
<h2 ref = {(element)=>{this.timeRef2=element}}>
{new Date().toLocalTimeString()}
</div>
)
}
//组建挂载完毕:组件第一次渲染完毕执行=>虚拟DOM已经完全转化为真实DOM
compomentDidMount(){
console.loh(this)//组件实例
console.loh(this.ref)//组件ref容器
setInterval(()=>{
//this.key = 真实DOM{对应此处的<h2>标签}
this.refs.timeRef.innerHTML = new Date().toLoacleTimeString();
this.refs.timeRef.innerHTML = new Date().toLoacleTimeString();
})
}
}
ReactDOM.render(<Clock />,document.getElementById("app"))
3.createRef实现
React中creatRef源码:
//a immutable object(不可改变的对象) with single mutable value
function creatRef(){
var refObject={
current:null;
};
{
Object.seal(refObject );
//seal封装,对参数对象进行封闭,不能添加新的属性,只能有一个属性
}
return refObject;
}
注意:
执行React.creatRef()=>返回{ current:null }对象容器,但是这个返回值源码没有挂载到组件实例上.
所以我们需要进行手动挂载this.key = React.createRef()上。
createRef实现自动化时钟
class Clock extends React.Component{
constructor(props){
super(props)
this.timeRef=React.createRef() //{current:null}
}
render(){
return(
<div>
通过createElement创建虚拟DOM,新增ref属性,
ReactDOM.render把虚拟DOM同步渲染成真实DOM=>判断是否有ref存在
如果有ref,会把ref对应的值,即{current:null}容器,将真实DOM<h2>赋值给容器current属性
和2的区别:
不需要给引用容器提供key
<h2 ref={e=>}>{new Date().toLocalTimeString()}</h2>
</div>
)
}
componentDidMount(){
console.log(this)
console.log(this.ref)
setInterval(()=>{
//this.key.current=真实DOM<h2>
this.timeRef,current.innerHTML = new Date().toLocalTimeString()
},1000)
}
}
2.业务场景(登录)=>ref模拟form表单收集
三种非受控表单解决方式
方式一:ref="key" 原理:this.refs={} => this.refs={key:真实DOM}
方式二:ref={e=>this.key=e} =>直接赋值this.key=真实DOM
方式三:直接调用react提供的方法createRef();this.key=React.createRef():{current:nulll}=>{current:真实DOM}
方式一:ref="key" 原理:this.refs={} => this.refs={key:真实DOM}
class Form extends React.Component{
console.log(this)
console.log(this.refs.inputRef) //真实DOM
console.log(this.refs.inputRef.value)
render(){
return(
<div>
<input type="text" ref="inputRef" />
<button onClick={this.handleClick}>commit</button>
</div>
)
}
}
方式二:ref={e=>this.key=e} =>直接赋值this.key=真实DOM
class Form extends React.Component{
console.log(this.inputRef2) //真实DOM
console.log(this.inputRef2.value) //获取input输入内容
render(){
return(
<div>
<input type="text" ref={e=>this.inputRefs2=e}/>
<button onClick={this.handleClick}>commit</button>
</div>
)
}
}
方式三:直接调用react提供的方法createRef();this.key=React.createRef()
class Form extends React.Component{
console.log(this.inputRef3) //非真实DOM,是个对象容器
console.log(this.inputRef3.current) //真实DOM
console.log(this.inputRef3.current.value) //获取input输入内容
constructor(){
super()
this.inputRef3=React.createRef()
}
render(){
return(
<div>
<input type="text" ref={this.inputRefs3}/>
<button onClick={this.handleClick}>commit</button>
</div>
)
}
}
事件绑定受控表单方式
class Form extends React.Component{
handleChange=>(e)=>{
console.log("onChange") //input输入框中每输入一个触发一次onChange
console.log(e.targrt.value)
}
render(){
return(
<div>
<input type="text" onChange={this.handleChange}/>
<button onClick={this.handleClick}>commit</button>
</div>
)
}
}
3.业务衍生场景=>按钮触发事件
class Form extends React.Component{
constructor(){
super();
this.inputRef = React.createRef()
}
handleClick=()=>{
alert( this.inputRef.current.value)
}
handleBlur=(e)={
console.log(e.target) //真实DOM
console.log(e.target.value) //输入框内容
alert(e.target.value);
}
render(){
return(
<div>
<input type="text" onBlur={this.handleBlur}/>
<input type="text" ref={this.inputRef}/>
<button onClick={this.handleClick}>commit</button>
</div>
)
}
}
ReactDOM.render(<Form />,document.getElementById("app"))
4.业务衍生场景=>表单自动获取焦点
class Form extends React.Component{
constructor(){
super();
this.inputRef = React.createRef()
}
handleClick=()=>{
this.inputRef.current.focus()
}
render(){
return(
<div>
<input type="text" ref={this.inputRef}/>
<button onClick={this.handleClick}>commit</button>
</div>
)
}
//已经渲染完毕,可以直接直接使用真实DOM
componentDidMount(){
this.inputRef.current.focus()
}
}
ReactDOM.render(<Form />,document.getElementById("app"))