Как сделать так, чтобы createRef / useRef не нацеливался на последнее значение. Но лучше пойти туда, где он должен

Не удается использовать useRef / createRef для получения любого другого div, кроме того, что было добавлено последним. Как я могу сделать это так, когда нажимается кнопка, изменяется ссылка на div.

Я пробовал использовать как useRef, так и createRef. Поскольку я хочу создать новый экземпляр ref, я больше изучил createRef, чем useRef. Я также играл с useEffect. Но мое решение не помогло мне с моей самой большой проблемой

Я сделал небольшой проект, содержащий 3 компонента, чтобы помочь вам понять, что я пытаюсь объяснить.

У меня также есть база данных, содержащая фиктивные данные -> в моем реальном проекте это не проблема. Это массив, содержащий объекты. [{'id': '1', 'name': 'first'}, ...]

Главный:

const MainComponent = () => {
    const dataRef = React.createRef(null) 

    React.useEffect (() => {
        if(dataRef && dataRef.current){
            dataRef.current.scrollIntoView({ behavior:'smooth', block:'start' })
       }
    },[dataRef])

    const _onClick = (e) => {
        dataRef.current.focus(); 
    }

    return(
        <>
        {data && data.map((entry, index) =>{
            return <ButtonList 
                key={index}
                entry={entry}
                onClick={_onClick}
            /> 
        })}

        {data && data.map((entry, index) =>{
            return <ListingAllData  
                key={index}
                dataRef={dataRef}
                entry={entry}
                index={index}/>
        })}
        </>
    )
}

Компонент кнопки

const ButtonList = ({ entry, onClick }) => {
    return <button onClick={onClick}>{entry.name}</button>
}

Компонент данных листинга

const ListingAllData = (props) => {
    const {entry, dataRef } = props; 
    return (
        <div ref={dataRef}>
            <p>{entry.id}</p>
            <p>{entry.name}</p>
        </div>
    );
}

Я консоль зарегистрировал data.current, он извлекает только последний элемент. Я надеялся, что он найдет ту кнопку, которую я нажал.


person Joak    schedule 02.07.2019    source источник


Ответы (2)


Я думаю, что основная идея здесь - создать динамические ссылки для каждого элемента (массива ссылок), поэтому при рендеринге приложения выбирается только последний.

const MainComponent = () => {
  const dataRefs = [];

  data.forEach(_ => {
    dataRefs.push(React.createRef(null));
  });

  const _onClick = (e, index) => {
    dataRefs[index].current.focus();
    dataRefs[index].current.scrollIntoView({
      behavior: "smooth",
      block: "start"
    });
  };

  return (
    <>
      {data &&
        data.map((entry, index) => {
          return (
            <ButtonList
              key={index}
              entry={entry}
              onClick={e => _onClick(e, index)}
            />
          );
        })}

      {data &&
        data.map((entry, index) => {
          return (
            <>
              <ListingAllData
                key={index}
                dataRef={dataRefs[index]}
                entry={entry}
                index={index}
              />
            </>
          );
        })}
    </>
  );
};

Создан рабочий пример в песочнице кода.

https://codesandbox.io/s/dynamic-refs-so25v

person Janiis    schedule 02.07.2019
comment
Я думал, что решение будет динамическим. Я вроде как решил это сегодня, но немного более неуклюже, чем то, что сделал ты. Спасибо! - person Joak; 02.07.2019

Спасибо Яниису за ответ, мое решение было:

в MainComponent

...
  const refs = data.reduce((acc, value) => {
    acc[value.id] = React.createRef();
    return entry;
  }, {});

  const _onClick = id => {
    refs[id].current.scrollIntoView({
      behavior: 'smooth', 
      block: 'start'
    }); 
  }
....

затем я передал его ребенку и сослался как

<div ref={refs[entry.id]}>
person Joak    schedule 02.07.2019