代码之家  ›  专栏  ›  技术社区  ›  BrownBe

如何在映射中使用react useref来定位dom

  •  0
  • BrownBe  · 技术社区  · 6 年前

    我正在寻找一个关于获取一个带有react的dom元素数组的解决方案 useRef() 钩子。

    例子:

    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>
    }
    

    我怎样才能做到这一点呢?

    1 回复  |  直到 5 年前
        1
  •  10
  •   skyboyer    6 年前

    useRef 只是和React的部分相似 ref (只有 current )

    小精灵 hook的目标是在渲染之间存储一些数据,并且更改这些数据不会触发重新渲染(不像 useState 做)。

    也只是温和的提醒:最好避免初始化循环中的钩子或 if . 它是 first rule of hooks .

    考虑到这一点,我们:

    1. 创建数组并将其保留在渲染之间 乌瑟夫
    2. 我们通过 createRef()
    3. 我们可以参考使用列表 .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>)
      }
      

    这是我们可以安全地修改数组(比如通过改变它的长度)。但别忘了 小精灵 不触发重新渲染。所以要改变长度来重新渲染我们需要 土地使用权 .

    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 钩子。原因: 裁判 在元素被呈现之后,s被绑定,因此在呈现期间第一次运行它还没有初始化。

        2
  •  0
  •   dotconnor    6 年前

    如果您提前知道数组的长度,在示例中这样做,您可以简单地创建一个参考数组,然后根据索引分配每个引用。

    const Component = () => {
      const items = Array.from({length: 2}, a => useRef(null));
      return (
        <ul>
          {['left', 'right'].map((el, i)) => (
            <li key={el} ref={items[i]}>{el}</li>
          )}
        </ul>
      )
    }