问题描述
我正在寻找关于使用 react useRef()
钩子获取 DOM 元素数组的解决方案.
I looking for a solution about get an array of DOM elements with react useRef()
hook.
示例:
const Component = () =>
{
// In `items`, I would like to get an array of DOM element
let items = useRef(null);
return <ul>
{['left', 'right'].map((el, i) =>
<li key={i} ref={items} children={el} />
)}
</ul>
}
我怎样才能做到这一点?
How can I achieve this?
推荐答案
useRef
只是部分类似于 React 的 ref
(只是对象的结构,只有 当前
).
useRef
is just partially similar to React's ref
(just structure of object with only field of current
).
useRef
钩子的目的是在渲染之间存储一些数据,并且改变这些数据不会触发重新渲染(不像 useState
那样).
useRef
hook is aiming on storing some data between renders and changing that data does not trigger re-rendering(unlike useState
does).
也只是温和的提醒:最好避免在循环或 if
中初始化钩子.这是钩子的第一条规则.
Also just gentle reminder: better avoid initialize hooks in loops or if
. It's first rule of hooks.
考虑到这一点,我们:
创建数组并通过
useRef
我们通过createRef()
我们可以使用.current
表示法来引用列表
we can refer to list by using .current
notation
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
.
This way we can safely modify array(say by changing it's length). But don't forget that mutating data stored by useRef
does not trigger re-render. So to make changing length to re-render we need to involve 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
- 它会引发错误.
Also don't try to access refs.current[0].current
at first rendering - it will raise an error.
说
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 是在元素渲染后绑定的,所以在渲染第一次运行时还没有初始化.
or access it in useEffect
hook. Reason: ref
s are bound after element is rendered so during rendering is running for the first time it is not initialized yet.
这篇关于如何在地图中使用 useRef 反应目标 DOM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!