useRef

使用场景

1 .获取子组件的实例,只有类组件可以使用
2 .在函数组件中定义一个全局变量,不会因为重复render重复声明,类似于组件的this.xxx

获取子组件实例

function Example(){
    const inputEl=useRef(null)
    
    function handleClick(){
        console.log(inputEl)
        inputEl.current.focus()
    }

    return (
        <>
        <input type="text" ref={inputEl}/>
        <button onClick={handleClick}>点击</button>
        </>
    )
}

类组件属性

1 .我们需要保证函数组件每次render之后,某些变量不会被重复声明,比如说Dom节点,定时器id等
2 .在类组件中,可以通过给类添加一个自定义属性来保留,比如this.xx
3 .虽然可以通过useState来保留变量的值,但是useState会触发组件render,这里完全是不需要的,需要使用useRef来实现

function App () {
    const [ count, setCount ] = useState(0)
    const timer = useRef(null)
    let timer2 
    
    useEffect(() => {
      let id = setInterval(() => {
        setCount(count => count + 1)
        console.log(timer2)
      }, 500)
  
      console.log('123‘)
    // 确实setInterval在里面跑逻辑,外面的没有改
      timer.current = id
      timer2 = id
      return () => {
        clearInterval(timer.current)
      }
    }, [])
  
    const onClickRef = useCallback(() => {
      clearInterval(timer.current)
    }, [])
  
    const onClick = useCallback(() => {
      clearInterval(timer2)
    }, [])
  
    return (
      <div>
        点击次数: { count }
        <button onClick={onClick}>普通</button>
        <button onClick={onClickRef}>useRef</button>
      </div>
      )
  }
export default App
//看起来不用ref也是可以实现的,难道这个bug已经修了吗??

4 .app组件每次render,都会重新声明一次timer2,好像不是吧,打印出来tmer2一直都是最初是的id..

文档

1 .useRef返回一个可变的ref对象,其.current属性被初始化为传入参数initialValue
2 .返回的ref兑现挂载组件的整个生命周期都保持不变
3 .useRef可以保存任何类型的值,类似于在class中使用this.xxx
4 .他创建的是一个普通的js对象,而useRef和自己创建一个对象的区别是,useRef会在每次渲染时返回对同一个ref对象
5 .当ref内容发生变化时,useRef是不会通知你的,变更.current属性也不会引发组件的重新渲染

forwardRef

1 .函数组件没有实例,所以函数组件无法像类组件一样接收ref属性
2 .forwardRef 可以在父组件中操作子组件的ref对象
3 .forwardRef可以将父组件中的ref对象转发到子组件的dom上
4 .子组件接收props,ref,作为参数

function Child(props,ref){
//子组件这里要把props和ref分开作为参数传进来
  return (
    <input type="text" ref={ref}/>
  )
}
Child = React.forwardRef(Child);
//其实就是在之前的组件外面包一层,父组件使用时没有任何区别的
function Parent(){
  let [number,setNumber] = useState(0); 
  // 在使用类组件的时候,创建 ref 返回一个对象,该对象的 current 属性值为空
  // 只有当它被赋给某个元素的 ref 属性时,才会有值
  // 所以父组件(类组件)创建一个 ref 对象,然后传递给子组件(类组件),子组件内部有元素使用了
  // 那么父组件就可以操作子组件中的某个元素
  // 但是函数组件无法接收 ref 属性 <Child ref={xxx} /> 这样是不行的
  // 所以就需要用到 forwardRef 进行转发
  const inputRef = useRef();//{current:''}
  function getFocus(){
    inputRef.current.value = 'focus';
    inputRef.current.focus();
  }
  return (
      <>
        <Child ref={inputRef}/>
        <button onClick={()=>setNumber({number:number+1})}>+</button>
        <button onClick={getFocus}>获得焦点</button>
      </>
  )
}

实现类似this的效果,可以在函数内访问到最新的数据

1 .可以简单的跳出

function Example(props) {
  // 把最新的 props 保存在一个 ref 中
  const latestProps = useRef(props);
  useEffect(() => {
    latestProps.current = props;
  });

  useEffect(() => {
    function tick() {
      // 在任何时候读取最新的 props
      console.log(latestProps.current);
    }

    const id = setInterval(tick, 1000);
    return () => clearInterval(id);
  }, []); // 这个 effect 从不会重新执行
}

refs补充

1 .我们利用render方法得到了一个App组件的实例,然后就可以对他做一些操作,但是在组件内,jsx是不会返回一个组件的实例的,只是一个ReactElement,只是告诉React被挂在的组件应该长什么样子,
2 .ref的意思就是组件被调用的时候会新建一个改组件的实例,然后ref指向这个实例
3 .可以通过ref获得DOM节点.人如果把refs放到React组件,就会获得组件的实例.这样可以调用组件的实例方法
4 .组件的ref可以通过findDomNode来返回生成的DOM


image.png

5 .为了防止内存泄露,所有组件卸载的时候都会把ref置为null

useRef在函数组件中的使用

1 .之前class的写法是可以随时绑定在class上,但是function的操作是不能简单绑定上去的.需要操作

app.js里面
const contentRef=useRef(null)
<Content ref={contentRef}>

content.js
import React,{useImperativeHandle} from 'react'
function Content(props,ref){
    function resetCount(){
      //做一些事情
    }

    useImperativeHandle(ref,()=>{
        resetCount,resetCount,
//一个是传递到外面的函数名,一个是里面的函数u
    })
}
export default React.ForwardRef(Count)

2 .useImperativeHandle中定义了resetCount,以及使用React.forward获取ref,在app中为content中定义ref属性,然后就可以在外部父组件中使用通过ref调用子组件的resetCount方法

3 .函数式组件的Ref是什么?就是里面暴露出来的东西
4 .绑定到HTML元素上,对应的DOM元素


image.png

5 .绑定在class组件,获取的class组件实例


image.png

React.createRef,useRef

1 .两者都是创建了一个包含current属性的对象,绑定ref时,对应的属性和函数都在current对应的对象中

2 .createRef创建的时React.RefObject类型.只能读

3 .useRef创建的是React.MutableRefObject,是可读写的.可以保存任何可变的值,使用方式类似于class组件的this实例变量
4 .对函数式组件可设置ref,且设置的ref是一个可变对象,存放组件的变量,也能通过useImperativeHandle访问函数式组件的方法.但是不能像ref设置到class组件和DOM元素上那样可以获取到实例

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容