赞
踩
//useState 使用状态值,第一个 hook //1.引入useState 钩子 import React, { useState, useRef } from 'react'; //计数器 function App() { const [count, setCount] = useState(0); const ref = useRef(0) const changeIncrementCount = () => { setTimeout(()=>{ setCount(ref.current += 1); },3000) } return ( <div> <h2>计数器</h2> count:{count} <button onClick={changeIncrementCount}>+</button> </div> ) } export default App;
useRef
返回一个可变的ref 对象,其.current
属性被初始化为传入的参数(initalValue
)const refContainer = React.useRef(initalValue);
1. useRef 是一个只能用于函数组件的方法。
2. useRef 是除字符串 ref、函数 ref、createRef 之外的第四种获取 ref 的方法。
3. useRef 在渲染周期内永远不会变,因此可以用来引用某些数据。
4. 修改 ref.current 不会引发组件重新渲染。
5. useRef 在每次重新渲染后都保持不变,而 createRef 每次都会发生变化
import React, { useRef } from 'react'; function App() { //1.创建 ref对象 let nameRef = useRef();//相当于createRef const mysubmit = () => { console.log("提交的信息是username:" + nameRef.current.value); } return ( <div> <h2>useRef</h2> <input ref={nameRef} type="text" placeholder="请输入用户名" /> <button onClick={mysubmit}>提交</button> </div> ) } export default App;
访问 DOM 节点 或 React 元素
- 尽管使用React时,我们推荐大家仅仅只关注数据,但也存在一些场景,我们需要去访问DOM节点才能达到目的
import React, {Component, createRef} from "react"; export default class Demo extends Component { textInput = createRef<HTMLInputElement>(); focusTextInput = () => { if (this.textInput.current) { this.textInput.current.focus(); } } render() { return ( <> <input type="text" ref={this.textInput} /> <button onClick={this.focusTextInput}>点击我让input组件获得焦点</button> </> ); } }
import React, {useRef} from "react"; export default function Demo() { const inputRef = useRef<HTMLInputElement>(null); const focusTextInput = () => { if (inputRef.current) { inputRef.current.focus(); } } return ( <> <input type="text" ref={inputRef} /> <button onClick={focusTextInput}>点击我让input组件获得焦点</button> </> ); }
- 思考一个问题,默认支持的
input
组件拥有.focus
方法,调用该方法,input
组件就能够获得焦点。- 那如果我们自己要封装一个
Input
组件,并且也希望该Input
组件能够拥有.focus
和.blur
方法,我们应该怎么办?
forwardRef
就能够达到这个目的。forwardRef
方法能够传递ref
引用,具体使用如下// 官网的案例
const FancyButton = React.forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// 你可以直接获取 DOM button 的 ref:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
import React, {forwardRef, useState, ChangeEvent} from 'react'; export interface InputProps { value?: string, onChange?: (value: string) => any } function Input({value, onChange}: InputProps, ref: any) { const [_value, setValue] = useState(value || ''); const _onChange = (e: ChangeEvent<HTMLInputElement>) => { const value = e.target.value; setValue(value); onChange && onChange(value); } return ( <div> 自定义Input组件 <input value={_value} onChange={_onChange} ref={ref} /> </div> ); } export default forwardRef(Input);
useImperativeHandle
可以让我们在使用ref
时自定义暴露给父组件的实例值
.focus
改个名字,或者返回其他额外的属性或者方法,我们可以使用useImperativeHandle
。import React, {useRef, useImperativeHandle, forwardRef, Ref, useState, ChangeEvent} from 'react'; export interface InputProps { value?: string, onChange?: (value: string) => any } export interface XInput { focus: () => void; blur: () => void; sayHi: () => void } function Input({value, onChange}: InputProps, ref: Ref<XInput>) { const inputRef = useRef<HTMLInputElement>(null); const [_value, setValue] = useState(value || ''); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current && inputRef.current.focus() }, blur: () => { inputRef.current && inputRef.current.blur() }, sayHi: () => { console.log('hello, world!'); } })); const _onChange = (e: ChangeEvent<HTMLInputElement>) => { const value = e.target.value; console.log(value); setValue(value); onChange && onChange(value); } return ( <div> 自定义Input组件 <input value={_value} onChange={_onChange} ref={inputRef} /> </div> ); } export default forwardRef(Input);
import React, { useRef, useState } from "react"; import Input from './components/Input'; import { Button } from "antd-mobile"; const Demo = () => { const textInput = useRef<any>(null); const [text, setText] = useState('') const focusTextInput = () => { if (textInput.current) { textInput.current.focus(); textInput.current.sayHi(); } } return ( <> <Input ref={textInput} onChange={setText} value={text} /> <Button onClick={focusTextInput}>点击我,input组件获得焦点</Button> <div>{text}</div> </> ); } export default Demo;
- 在函数组件中,因为每次
re-render
就意味着函数重新执行一次,因此在函数内部保持变量引用是一件我们需要思考的事情- 这时候就可以利用 ref 的
.current
setInterval
的执行结果timer
的引用,才能准确的清除对应的定时器。import React, { useRef, useEffect } from 'react'; export default function Timer() { const timerRef = useRef<NodeJS.Timeout>(); useEffect(() => { timerRef.current = setInterval(() => { console.log('do something'); }, 1000); // 组件卸载时,清除定时器 return () => { timerRef.current && clearInterval(timerRef.current); } }, []); return ( <div> // ... </div> ) }
注意:useRef
和useState
不同,如果一个状态或者数据会影响DOM的渲染结果,一定要避免使用useRef来保持引用
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。