本文介绍了如何在地图中使用 useRef 反应目标 DOM的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找关于使用 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.

考虑到这一点,我们:

  1. 创建数组并通过 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 钩子中访问它.原因:refs 是在元素渲染后绑定的,所以在渲染第一次运行时还没有初始化.

or access it in useEffect hook. Reason: refs are bound after element is rendered so during rendering is running for the first time it is not initialized yet.

这篇关于如何在地图中使用 useRef 反应目标 DOM的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-06 21:54