How target DOM with react useRef in map

后端 未结 3 1912
一生所求
一生所求 2020-12-04 23:48

I looking for a solution about get an array of DOM elements with react useRef() hook.

example:

const Component = () => 
{

  // In `         


        
3条回答
  •  没有蜡笔的小新
    2020-12-05 00:41

    useRef is just partially similar to React's ref(just structure of object with only field of current).

    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.

    Having this in mind we:

    1. create array and keep it between renders by useRef
    2. we initialize each array's element by createRef()
    3. 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 (
        {['left', 'right'].map((el, i) =>
      • )}
      ) }

    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 (<>
        
      {refs.current.map((el, i) =>
    • )}
    ) }

    Also don't try to access refs.current[0].current at first rendering - it will raise an error.

    Say

          return (
      {['left', 'right'].map((el, i) =>
    • {refs.current[i].current.value}
    • // cannot read property `value` of undefined )}
    )

    So you either guard it as

          return (
      {['left', 'right'].map((el, i) =>
    • {refs.current[i].current && refs.current[i].current.value}
    • // cannot read property `value` of undefined )}
    )

    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.

提交回复
热议问题