问题描述
我正在寻找一个关于使用react useRef()
hook来获取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
hook的目标是在渲染之间存储一些数据并更改该数据不会触发重新渲染(与 useState
不同) 。
useRef
hook is aiming on storing some data between renders and changing that data does not trigger re-rendering(unlike useState
does).
同样温和提醒:最好避免在循环中初始化挂钩或如果。这是钩子的第一条规则。
Also just gentle reminder: better avoid initialize hooks in loops or if
. It's first rule of hooks.
记住这一点我们:
- 创建数组并保留它之间的渲染
useRef
- 我们通过
createRef()
初始化每个数组的元素 -
我们可以使用
.current
表示法来引用列表
- create array and keep it between renders by
useRef
- we initialize each array's element by
createRef()
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 was 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.
Say
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
hook中访问它。原因: 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.
这篇关于目标DOM如何在map中反应useRef的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!