在一些特殊情况下,React也需要对DOM进行一些操作,这时就要用到——ref。
理解ref
1)例子:用上一节的Counter.js项目来理解,实现获取增加按钮距离浏览器窗口顶部的距离。
import React,{ Component,Fragment } from 'react'; import Child from './Child' class Counter extends Component{ constructor(props) { super(props); this.handleBtnClick = this.handleBtnClick.bind(this); this.state = { counter:1 } } handleBtnClick(){ // console.log(this.buttonElem);//button节点 // console.log(this.buttonElem.clientTop); const newCounter = this.state.counter + 1; this.setState({ counter:newCounter }); } render() { return ( <Fragment> <button onClick = {this.handleBtnClick} ref = {(button) => {this.buttonElem = button}} > 增加 </button> <Child number = {this.state.counter}/> </Fragment> ) } } export default Counter;
ref 写在html标签上,获取的是DOM节点;
ref 写在组件标上,获取的是组件的JS实例。
2)setState是异步的!
import React,{ Component,Fragment } from 'react'; class Counter extends Component{ constructor(props) { super(props); this.handleBtnClick = this.handleBtnClick.bind(this); this.state = { counter:1 } } handleBtnClick(){ const newCounter = this.state.counter + 1; console.log(this.divElem.innerHTML);//第一个 this.setState({ counter:newCounter }); console.log(this.divElem.innerHTML);//第二个 } render() { return ( <Fragment> <button onClick = {this.handleBtnClick} >增加</button> <div ref = {(div)=>{this.divElem = div}}>{this.state.counter}</div> </Fragment> ) } } export default Counter;
上面的代码中,每当点击一次按钮,两个console输出的都是相同的数字,这是因为setState是异步的,在第二个cosole执行时,可能还没有执行它,因此没有输出更改后的值。
我们可以将setState方法做一些修改,在里面传递两个函数参数,在setState把数据改变之后会执行第二个函数,这时第二个console输出的就是改变后的值了!
handleBtnClick(){ const newCounter = this.state.counter + 1; console.log(this.divElem.innerHTML); this.setState(() => { return { counter:newCounter } },()=>{ console.log(this.divElem.innerHTML); }) }
ref小练习
需求:在input中输入内容,当点击按钮之后,通过ref获取Dom节点的内容,把获取出来的内容输出在控制台。
以下是我的实现代码:
import React,{ Component,Fragment } from 'react'; class Ref extends Component{ constructor(props) { super(props); this.handleInputElem = this.handleInputElem.bind(this); this.handleInputChange = this.handleInputChange.bind(this); this.state = { content:'' } } handleInputElem() { const newContent = this.state.content; this.setState(()=>{ return { content:newContent } },()=>{ console.log(this.inputElem.value); }); } handleInputChange(e) { this.setState({ content:e.target.value }) } render() { return ( <Fragment> <input value = {this.state.content} ref = {(input)=>{this.inputElem = input}} onChange = {this.handleInputChange}></input> <button onClick = {this.handleInputElem}>提交</button> </Fragment> ) } } export default Ref;