Прокрутите до просмотра в React
Я делаю простое приложение для реагирования, где есть два разных div's..
Один с выбранным входом и выбранным списком,
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
Другой будет перечислять выбранную опцию как fieldset,
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
На основе этого решения я добавил createRefк выбранному элементу, например,
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Затем я использовал методы запроса Javascript, чтобы получить такие элементы DOM, как,
const chipsArray = document.querySelectorAll("#container > div > .chip");
Добавлен прослушиватель событий щелчка ко всем элементам, таким как,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Тогда scrollSmoothHandlerвроде,
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
Но это не так, как ожидалось.
Требование:
При щелчке по любому элементу first div, связанный с ним набор полей должен попасть smooth scrolledв другой div.
Например: если пользователь щелкнет элемент Item Fourпод<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
затем необходимо прокрутить соответствующий набор полей. Здесь набор полей с легендой как Item Four..
Я также думаю, что методы запроса js dom реагируют, и это не похоже на способ реализации. Может ли кто-нибудь помочь мне добиться результата прокрутки к соответствующему набору полей при щелчке по выбранному элементу ..
Ответы
Проблема
React.createRefдействительно только в компонентах на основе классов. При использовании в теле функционального компонента ссылка будет воссоздаваться в каждом цикле рендеринга.- Не используйте селектор запросов DOM для присоединения
onClickслушателей к элементам DOM. Они живут снаружи и реагируют, и вам нужно не забыть очистить их (то есть удалить), чтобы не было утечки памяти. ИспользуйтеonClickопору React . - Когда
selectedElementsони отображаются, вы прикрепляете один и тот же ref к каждому элементу, поэтому последний набор - это тот, который получает ваш пользовательский интерфейс.
Решение
- Используйте
React.useRefв теле функционального компонента для хранения массива ссылок на реакцию для присоединения к каждому элементу, который вы хотите просмотреть. - Прикрепление
scrollSmoothHandlerнепосредственно к каждомуspan«SonClickопоре. - Прикрепите каждую ссылку из массива ссылок, созданного в 1. к каждому набору сопоставленных полей, к которому вы хотите прокрутить.
Код
import React, { createRef, useRef } from "react";
import { render } from "react-dom";
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
// React ref to store array of refs
const scrollRefs = useRef([]);
// Populate scrollable refs, only create them once
// if the selectedElements array length is expected to change there is a workaround
scrollRefs.current = [...Array(selectedElements.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
// Curried handler to take index and return click handler
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
{selectedElements.map((el, i) => (
<span
className="chip _7ahQImy"
onClick={scrollSmoothHandler(i)} // <-- pass index to curried handler
>
{el}
</span>
))}
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div
key={i}
className="selected-element"
ref={scrollRefs.current[i]} // <-- pass scroll ref @ index i
>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};
Решение # 2
Поскольку вы не можете обновлять какие-либо элементы в divwith, id="container"а все onClickобработчики должны быть присоединены с помощью запроса к DOM, вы все равно можете использовать каррированный scrollSmoothHandlerобратный вызов и заключить индекс в область видимости. Вам понадобится useEffectловушка для запроса DOM после первоначального рендеринга, чтобы промежутки были смонтированы, и useStateловушка для сохранения «загруженного» состояния. Состояние необходимо для запуска повторной визуализации и повторного включения scrollRefsв scrollSmoothHandlerобратный вызов.
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
const [loaded, setLoaded] = useState(false);
const scrollRefs = useRef([]);
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
useEffect(() => {
const chipsArray = document.querySelectorAll("#container > div > .chip");
if (!loaded) {
scrollRefs.current = [...Array(chipsArray.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler(index));
});
setLoaded(true);
}
}, [loaded]);
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollRefs.current[i]}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};