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