在class组件中我们会用render返回一系列的组件或者DOM节点,有时我们需要获取某一个DOM节点或者子组件的实例,然后去对他进行一些手动的操作,我们可以在componentDidMount生命周期函数内通过DOM选择器来获取对应的DOM对象,但是这不是很方便,因为很多需要都需要我们保存对应的DOM对象的引用,管理起来也有点麻烦。
我们可以用ref来获取某个子节点的实例,然后通过当前class组件实例的一些特定属性来直接获取子节点实例。(vue里也有一个ref属性,通过this.$refs来获取DOM实例,两个差不多的)
ref有三种实现方法:
- 字符串格式 ;字符串格式,这是React16版本之前用得最多的。 ;例如:<p ref="info">span</p>
- 函数格式 ;ref对应一个方法,该方法有一个参数,也就是对应的节点实例 ;例如:<p ref={ele => this.info = ele}></p>
- createRef方法 ;React16提供的一个API,使用React.createRef()来实现
方法一 字符串格式
我们可以在render函数内返回的jsx代码片段中,给某个DOM节点或者子组件设置一个ref属性,传递一个字符串,这样当当前组件渲染完成后,我们可以通过当前class组件实例上的refs属性获取对应的一个DOM对象或者子组件实例
比如jsx中有这样的一个代码片段:<p ref="info">span</p>,之后我们就可以通过this.refs.info获取到该p元素渲染后生成的DOM实例了。
举个例子:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} componentDidMount = ()=>{ this.refs.info.textContent = "no = "+this.state.no } //组件挂载完成后设置this.ref.info这个DOM节点的textContext test=()=>{ this.refs.info.textContent= "no = "+ ++this.state.no } //点击测试按钮后也修改this.ref.info这个DOM节点的textContext render(){ return ( <div> <button onClick={this.test}>测试</button> <p ref="info"></p> </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
效果如下:
writer by:大沙漠 QQ:22969969
初始化时在componentDidMount生命周期函数内通过this.refs.info获取到p元素的节点,之后设置它的textContext属性,另外在测试按钮上也绑定了一个test属性,每次店家时递增this.state.no,并设置在this.refs.info这个DOM节点上,也就是p节点对象了。
方法二 函数格式
上面例子里符串格式的ref在内部会转换为一个函数格式,我们也可以直接将ref属性的值设置为一个函数,该函数可以传入一个参数,值是当前的DOM对象实例,比如:<p ref={ele => this.info = ele}></p>,这样我们在当前class组件内可以直接通过this.info获取到这个P元素的DOM对象实例了。
我们改写一下上面的例子,用函数格式来写一下,如下:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} componentDidMount = ()=>{ this.info.textContent = "no = "+this.state.no } test=()=>{ this.info.textContent= "no = "+ ++this.state.no } render(){ return ( <div> <button onClick={this.test}>测试</button> <p ref={ele => this.info = ele}></p> //这里以函数的形式来写,在其它逻辑内只需通过this.info就可以获取这个p节点实例了 </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
运行的效果和第一个例子是一样了,就不截图了。
方法三 createRef方法
createRef是React16新增的一个API,也是用于设置ref的,使用时,我们需要先执行
React.createRef()
执行后将返回一个{current: null}这样的对象,我们在jsx内将React.createRef()的返回值作为值设置在一个DOM节点的ref属性上,渲染后该DOM对象就会保存到React.createRef()返回的对象里的current属性上了。
还是改写一下第一个例子,我们用createRef方法来写一下,如下:
<div id="root"></div> <script type="text/babel"> class RefDemo extends React.Component{ state = {no:1} domp = React.createRef(); //执行React.createRef()返回一个{current:null}对象 componentDidMount = ()=>{ this.domp.current.textContent = "no = "+this.state.no } test=()=>{ this.domp.current.textContent= "no = "+ ++this.state.no } render(){ return ( <div> <button onClick={this.test}>测试</button> <p ref={this.domp}></p> //设置ref属性,值直接指向React.createRef()的返回值即可,也就是当前的domp属性,之后在其它地方可以直接使用this.domp.current获取这个P实例了 </div> ) } } ReactDOM.render(<RefDemo></RefDemo>,root) </script>
运行的效果和第一个例子也是一样,这里也不贴截图了,如果把ref设置在一个子节点组件上,则获取的是组件实例。
除了普通DOM节点或自组件的节点外,如果我们在jsx代码里引用了一个函数组件,由于在React当中函数组件也是返回jsx的,本身是没有实例的,因此我们设置ref属性获取到的值是为空的,此时可以用React.forwardRef()来解决,React.forwardRef也是用到了createRef()方法,具体的我们下篇文章再讲解。