前端杂记

useRef

2020-06-22  本文已影响0人  skoll

使用场景

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 从不会重新执行
}
上一篇下一篇

猜你喜欢

热点阅读