#reactjs
#reactjs
Вопрос:
Это первый раз, когда я использую перехваты react. Я пытаюсь отключить выборку, используя состояние (логическое значение). Но есть проблема, потому что функция все еще видит начальное состояние и выполняет функцию десятки раз вместо одного раза. Я не вижу смысла. В консоли реагирования состояние помечено как true и по-прежнему передает мой оператор if
Я заметил факт, что без прослушивателя в окне он работает. Итак, я попытался использовать сборку событий в React — onScroll, но это не решило мою проблему — ничего не произошло. Моя версия React: 16.8.6
const [isFetchedData, setIsFetchedData] = useState(false);
const fetchBookData = async () => {
await setisFetchedData(true);
... - fetchedData
setTimeout(() => {
setIsFetchedData(false);
}, 5000); --- I would like to make available to fetch data again after 5 seconds.
};
useEffect(() => {
window.addEventListener("scroll", scrollHandler);
});
const scrollHandler = () => {
if (!isFetchedData) {
fetchBookData(); --- always executing
}
};
Fleischpflanzerl — я поместил эту функцию в тело useEffect. Функция scrollHandler сейчас не выполняется. Можете ли вы привести мне несколько примеров, как это исправить?
useEffect(() => {
return () => {
window.addEventListener("scroll", scrollHandler, true);
const scrollHandler = () => {
if (!isFetchedData) {
// fetchBookData();
console.log("fetch");
}
};
};
}, [isFetchedData]);
Комментарии:
1. Похоже, вам нужно поместить
scrollHandler
тело внутри функции, которую вы передаете в useEffect hook. Проверьте эту проблему, она как раз об этом (плюс второй аргумент для useEffect, он же deps): github.com/facebook/react/issues/14920 .2. @Fleischpflanzerl — по-прежнему не работает: (Я вставляю свой код в основной пост
Ответ №1:
Я думаю, вам следует использовать useRef
вместо useState
в этой ситуации.
Что не так, когда вы вызываете useState?
Если вы вызываете setIsFetchedData
set isFetchedData
, вы запускаете повторную визуализацию в своем компоненте. Таким образом, каждый раз, когда вы прокручиваете, вы запускаете повторный рендеринг компонента.
Основная проблема заключается в том, что isFetchedData
это просто логическое значение в вашем перехвате. Не волшебная переменная, которая мгновенно меняет ее значение. (React только ставит повторный рендеринг в очередь, он не будет повторен немедленно.)
Но когда события прокрутки происходят несколько раз, функция обработчика событий будет отображаться isFetchedData
как статическая false
. И если это false
так, вы звоните fetch
еще раз.
Дело в том, что это isFetchedData
не изменится до тех пор, пока следующий повторный рендеринг не вызовет useState
еще раз.
Еще одна проблема в вашем коде — вы забыли определить функцию очистки и зависимости. При каждом рендеринге React вызывает useEffect
, поэтому, если вы не возвращаете функцию очистки и не определяете зависимости, которые сообщают React, когда запускать этот эффект, вы вызываете addEventListener
каждый раз, когда компонент повторно визуализирует и присоединяет обработчик несколько раз.
Я сделал рабочий пример с useRef, который, возможно, стоит больше тысячи слов.
const useRef = React.useRef;
const useEffect = React.useEffect;
const useScrollFetch = () => {
const isFetchedData = useRef(false);
function fakeFetchBookData() {
console.log("fakeFetchBookData start...");
setTimeout(() => {
console.log("fakeFetchBookData end...");
}, 2000);
}
function fetchBookData() {
isFetchedData.current = true;
fakeFetchBookData();
setTimeout(() => {
console.log("isFetchedData reset");
isFetchedData.current = false;
}, 5000); // I would like to make available to fetch data again after 5 seconds.
}
const scrollHandler = event => {
if (!isFetchedData.current) {
console.log(
"scrollHandler: ",
event.type,
"isFetchedData: ",
isFetchedData
);
fetchBookData();
}
};
useEffect(() => {
window.addEventListener("scroll", scrollHandler, true);
return () => {
window.removeEventListener("scroll", scrollHandler, true);
};
}, []);
};
function App() {
console.log("App render...");
useScrollFetch();
return (
<div className="App" style={{ width: '10%' }}>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed
dictum, enim vitae porttitor vulputate, sem nulla faucibus
felis, a faucibus ex lacus at mauris. Mauris scelerisque rhoncus
nisi vel commodo. Suspendisse varius lectus porta lectus
commodo, consectetur condimentum nibh euismod. Aenean cursus
nibh erat, non rhoncus arcu porta vel. Pellentesque maximus
mauris nec neque porttitor commodo. In condimentum hendrerit
augue, vitae lobortis est iaculis quis. Fusce vehicula sit amet
dui vel dignissim. Donec tempus hendrerit tristique. Nam
suscipit aliquet nisl eu malesuada.
</p>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<div id="root"></div>
<script src="https://unpkg.com/react@16.8.6/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16.8.6/umd/react-dom.production.min.js"></script>
(Мне пришлось удалить async / await, потому что я не могу встроить сюда код с этим синтаксисом, но это не проблема.)
Я действительно предлагаю прочитать Полное руководство по useEffect от Дэна Абрамова. Это очень помогло мне лучше понять, как работает useEffect. 🙂