Cómo el DOM objective reactjs con useRef en el mapa

Estoy buscando una solución para obtener una matriz de elementos DOM con el useRef() reaccion useRef() .

ejemplo:

 const Component = () => { // In `items`, I would like to get an array of DOM element let items = useRef(null); return 
    {['left', 'right'].map((el, i) =>
  • )}
}

¿Cómo puedo conseguir esto?

Si conoce la longitud de la matriz antes de tiempo, a lo que hace en su ejemplo, simplemente puede crear una matriz de referencias y luego asignar cada una por su índice:

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

useRef es solo parcialmente similar a la ref de React (solo estructura de objeto con solo campo de current ).

useRef hook apunta a almacenar algunos datos entre representaciones y cambiar que los datos no activan la representación (a diferencia de useState ).

También un recordatorio suave: es mejor evitar inicializar los ganchos en bucles o if . Es la primera regla de los ganchos .

Teniendo esto en cuenta nosotros:

  1. crear una matriz y mantenerla entre renders por useRef
  2. Inicializamos los elementos de cada matriz mediante createRef()
  3. Podemos referirnos a la lista usando .current notation

     const Component = () => { let refs = useRef([React.createRef(), React.createRef()]); useEffect(() => { refs.current[0].current.focus() }, []); return (
      {['left', 'right'].map((el, i) =>
    • )}
    ) }

Esto fue que podemos modificar la matriz de forma segura (por ejemplo, cambiando su longitud). Pero no olvide que la mutación de los datos almacenados por useRef no desencadena la nueva representación. Por lo tanto, para hacer que la longitud del cambio se useState involucrar a 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) =>
  • )}
) }

Tampoco intente acceder a refs.current[0].current en la primera renderización: generará un error.

Decir

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

Así que o lo guardas como

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

o accede a él en useEffect hook. Motivo: los ref están vinculados después de que el elemento se representa, por lo que durante la representación se ejecuta por primera vez, aún no se ha inicializado.