score:2
In order to listen the changes in your state from inside the useEffect
callback (when you're not following any props update), you can save your state in a variable outside your component's scope, and using it instead of the state directly.
Here you have the code:
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
const debounce = (func, wait, immediate) => {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => {
timeout = null;
if (!immediate) func.apply(context, args);
}, wait);
if (immediate && !timeout) func.apply(context, args);
};
};
let isFetchingState;
const App = () => {
const [isFetching, setIsFetching] = useState(false);
isFetchingState = isFetching;
const handleScroll = debounce(() => {
setIsFetching(!isFetchingState);
console.log({ isFetchingState });
}, 300);
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return <div style={{ height: "1280px" }}>Hello world</div>;
};
const root = document.getElementById("root");
if (root) ReactDOM.render(<App />, root);
score:1
You have passed an empty array as a second argument to useEffect. And this is what your key issue for not being called useEffect again after it is run.
To solve the issue, just don't pass the second argument.
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
});
Or, call the useEffect whenever the property being changed:
useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [isFetching]); // re-run useEffect on isFetching changed
This is similar to what we do in componentDidUpdate:
if (prevState.count !== this.state.count) {
// do the stuff
For more detail, see the documentation itself.
A note from the docs:
If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.
If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often. Also, don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.
score:4
Add isFetching
as a dependency to useEffect
While i can't provide a deep explanation, I can say that you basically lied to React in useEffect
when you said the effect doesn't depend on anything by providing an empty array of dependencies it's always good to pass all the variables that include in your effect.
Also you create a new function every time the component re-render
, to avoid this move the function inside of useEffect
or wrap it inside useCallback
which will not create re-create the function unless something in the array of dependencies changes
useEffect(
() => {
const handleScroll = debounce(() => {
setIsFetching(prevState => !prevState);
console.log({ isFetching });
}, 300);
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
},
[isFetching]
);
Or with useCallback
const handleScroll = useCallback(
debounce(() => {
setIsFetching(prevState => !prevState);
console.log({ isFetching });
}, 300),
[isFetching]
);
useEffect(
() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
},
[isFetching]
);
Source: stackoverflow.com
Related Query
- React hook not updated in function listened on scroll event
- Function not correctly reading updated state from React hook state
- React setState hook from scroll event listener
- Uncaught TypeError: create is not a function using useEffect React Hook with AJAX request
- React hooks value is not accessible in event listener function
- React + TypeScript: Scroll event type not assignable to window.addEventListener
- React .createClass() scroll to ref: scrollIntoView not a function
- React onClick event not firing when function is passed to child
- React - State Hook map is not a function
- React - State Hook map is not a function
- Why react calls function in subcomponents event when this subsomponents not rendered?
- why updated state not reflected inside an event listener: React Native, Hooks
- Why react hook value is not updated in async function?
- React - < Input> value is not getting updated on onChange event
- React Custom Hook set function returned is not a function
- React keypress event taking only initial state values and not updated values
- React Material-UI Select not detecting scroll event
- Not able to access react state from socket event handler function
- TypeError: e.preventDefault is not a function on React Hook Form using EmailJs
- React event listener function not called
- Mouse scroll event Is not working for react select inside react scrollbar
- Firebase auth and React Hook - returning function from hook not working
- React hook is not working from event handler
- Function called from a react custom hook returns 'is not a function'
- React hooks not returning updated state values inside callback function from library events (FabricJS)
- React hooks updated state not passed to function
- React useState hook (and useEffect) not working in callback function
- The state variable returned after using useState react hook shows .map is not a function
- React custom hook with event listener not works while updating the state
- updated state value are not updated inside function in react
More Query from same tag
- React useEffect hook infinity loop
- Tic-Tac-Toe using React JS
- What is the best approach for adding class and styles without re-render - reactjs
- Node.js/React Form submission
- React Reloading Page doesn't work on Server, but works on localhost
- Update object across array of objects using setState
- How to implement auto logout functionality if a user logs out and then logs in before previous setTimeout ends?
- How Insert data to two tables at once?
- Testing react component - TypeError: data.map is not a function
- Passing function via props from Parent to Child component in React?
- Watching state from child component React with Material UI
- How to use state in react project
- React Hooks useState() with Object
- Updating specific fields in reactJS
- How to load child component with props on first render with React Hooks
- React Redux re-fetch data using state and state change
- Why cant I separate <Switch> to a different module?
- Datepicker with React on Safari
- how can I dynamically get the variables in javascript?
- How to make Select menu location relative to controller button in React?
- Unable to send POST request from the React frontend to Django Rest Framework using serializer?
- How to implement a React equivalent of Vue's IS attribute?
- How to wait 'return' until 'dispatch' finish
- React Hook Conditional Render
- custom http hook using axios
- When using getDerivedStateFromProps (React) getting error: Cannot read property 'setState' of null
- setState from input on change - can't delete from input
- Material UI disable Menu transition
- Webpack 4 Babel and React error in handling the JSX files
- ComponentDidUpdate Variable Not Defined