useRef
只是部分类似于 React ref
(只是对象的结构,只有 字段current
)。
useRef
hook 的目标是在渲染之间存储一些数据,并且更改该数据不会触发重新渲染(不像useState
那样)。
也只是温和的提醒:最好避免在循环或if
. 这是 hooks的第一条规则。
考虑到这一点,我们:
创建数组并将其保留在渲染之间 useRef
我们初始化每个数组的元素 createRef()
我们可以使用.current
符号来引用列表
const Component = () => {
let refs = useRef([React.createRef(), React.createRef()]);
useEffect(() => {
refs.current[0].current.focus()
}, []);
return (<ul>
{['left', 'right'].map((el, i) =>
<li key={i}><input ref={refs.current[i]} value={el} /></li>
)}
</ul>)
}
这样我们就可以安全地修改数组(比如通过改变它的长度)。但是不要忘记存储的变异数据useRef
不会触发重新渲染。因此,要更改长度以重新渲染,我们需要涉及useState
.
const Component = () => {
const [length, setLength] = useState(2);
const refs = useRef([React.createRef(), React.createRef()]);
function updateLength({ target: { value }}) {
setLength(value);
refs.current = refs.current.splice(0, value);
for(let i = 0; i< value; i++) {
refs.current[i] = refs.current[i] || React.createRef();
}
refs.current = refs.current.map((item) => item || React.createRef());
}
useEffect(() => {
refs.current[refs.current.length - 1].current.focus()
}, [length]);
return (<>
<ul>
{refs.current.map((el, i) =>
<li key={i}><input ref={refs.current[i]} value={i} /></li>
)}
</ul>
<input value={refs.current.length} type="number" onChange={updateLength} />
</>)
}
也不要尝试refs.current[0].current
在第一次渲染时访问- 它会引发错误。
说
return (<ul>
{['left', 'right'].map((el, i) =>
<li key={i}>
<input ref={refs.current[i]} value={el} />
{refs.current[i].current.value}</li> // cannot read property `value` of undefined
)}
</ul>)
所以你要么保护它
return (<ul>
{['left', 'right'].map((el, i) =>
<li key={i}>
<input ref={refs.current[i]} value={el} />
{refs.current[i].current && refs.current[i].current.value}</li> // cannot read property `value` of undefined
)}
</ul>)
或在useEffect
钩子中访问它。原因:ref
s 在元素渲染后被绑定,所以在渲染过程中第一次运行它尚未初始化。