0

I create simple custom hook that save the screen height and width . The problem is that I want to re-render(update state) only if some condition in my state is happened and not in every resize event.. I try first with simple implementation :

const useScreenDimensions = () => {
  const [height, setHeight] = useState(window.innerWidth);
  const [width, setWidth] = useState(window.innerHeight);
  const [sizeGroup, setSizeGroup]useState(getSizeGroup(window.innerWidth));

 useEffect(() => {
  const updateDimensions = () => {
   if (getSizeGroup() !== sizeGroup) {
    setSizeGroup(getSizeGroup(width));
    setHeight(window.innerHeight);
    setWidth(window.innerWidth);
  }
};

  window.addEventListener('resize', updateDimensions);
  return () => window.removeEventListener('resize', updateDimensions);
  }, [sizeGroup, width]);

 return { height, width };

}

The problem with this approach is that the effect calls every time , I want that the effect will call just once without dependencies (sizeGroup, width) because I don't want to register the event every time there is a change in screen width/size group(window.addEventListener).

So, I try with this approach with UseCallBack , but also here my 'useEffect' function called many times every time there is any change in the state..

//useState same as before..
const updateDimensions = useCallback(() => {
  if (getSizeGroup(window.innerWidth) !== sizeGroup) {
  setSizeGroup(getSizeGroup(width));
  setHeight(window.innerHeight);
  setWidth(window.innerWidth);
}
}, [sizeGroup, width]);

useEffect(() => {
 window.addEventListener('resize', updateDimensions);
 return () => window.removeEventListener('resize', updateDimensions);
}, [updateDimensions]);

....
return { height, width };

The question is what the correct and effective way for my purposes? I want just "register" the event once, and update the my state only when my state variable is true and not every time the width or something else get updated..

I know that when you set empty array as second argument to 'UseEffect' it's run only once but in my case I want that the register of my event listener run once and on resize I will update the state only if some condition is true

Thanks a lot.

2
  • Possible duplicate of How to call loading function with React useEffect only once Commented Apr 29, 2019 at 4:29
  • @HenryMueller it's not duplicate . I know that when you set empty array as second argument to 'UseEffect' it's run only once but in my case I want that the register of my eventlistner run once and on resize I will update the state only if some condition is true... Commented Apr 29, 2019 at 6:18

1 Answer 1

1

use 2 different useEffect

first one for register event.So below code will run at the time of componentDidMount.

useEffect(() => {
  window.addEventListener('resize', updateDimensions);
}, []);

second useEffect to run based on state change.

useEffect(() => {
   updateDimensions();
   return () => window.removeEventListener('resize', updateDimensions);
}, [sizeGroup, width])


const updateDimensions = useCallback(() => {
 setSizeGroup(getSizeGroup(width));
 setHeight(window.innerHeight);
 setWidth(window.innerWidth);     
}

I'm not sure useCallback function need to use or not. And I've not tested this code.

Sign up to request clarification or add additional context in comments.

10 Comments

Tnx, I try that but in this case eslint plugin 'force' me to set 'updateDimensions' function as dependency to the first 'useEffect' function , then what happend it's called every time there is a change in the state.. he want that dependency because in updateDimensions func I check some condition if to update state or not (sizegroup- you don't check that so maybe in your case eslint will not force you to set the func as dependency )
if you're passing [sizeGroup, width] to useEffect then you don't need to check condition. react hooks figure-out for you that when I need to run this function. so no need to if else condition.
So if sizeGroup and/or width will change only at that time updateDimensions function will call otherwise it'll not call.
setters have a functional form setWidth(oldWidth => newWidth) to be able to remove the dependency on width...
I think I just give up on 'group' under state and create function that calculate me the group by old width and new width like @Aprillion write , then I can set new width to state only if group are different. I don't see another way to think how can I update my width without dependency on group...
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.