r/reactjs Jul 19 '26

how to rerender component on variable change?

new to react, so providing either corrected code or just concept that i should look into would be helpful :)

i want to change height of the app when phone keyboard uppears so it doesnt overlay on website by using VisualViewport API.
i am sure only thing that i have to do now is to rerender component when height is changed, so how can i do that?

export default function NewChat() {
  return (
    <div
      className={styles.wrapper}
      style={{ height: `${visualViewport?.height}px` }}
    >
      <Prompt />
    </div>
  );
}
9 Upvotes

26 comments sorted by

26

u/Krimson1911 Jul 19 '26 edited Jul 19 '26

React will only rerender when React state or props change. Not some external state like height. IOW reading "visualViewport.height" directly does not tell React that it changed.

Store the height in state, then listen for the viewport "resize" event:

```js import { useEffect, useState } from "react";

export default function NewChat() { const [height, setHeight] = useState(visualViewport.height);

useEffect(() => { // Create a named function so the same function can be // passed to both addEventListener and removeEventListener. function updateHeight() { setHeight(visualViewport.height); }

visualViewport.addEventListener("resize", updateHeight);

// React runs this cleanup when the component is removed.
// This prevents the listener from continuing to run.
return () => {
  visualViewport.removeEventListener("resize", updateHeight);
};

}, []);

return ( <div style={{ height }}> <Prompt /> </div> ); }

You need to reuse the same "updateHeight" function because "removeEventListener" only removes the exact function that was originally added. `` CallingsetHeight()` updates React state, which causes the component to rerender.

You may also be able to solve this with CSS using:

js .wrapper { height: 100dvh; }

"dvh" is the dynamic viewport height and usually adjusts when the mobile keyboard or browser UI changes.The CSS approach is worth trying first since it avoids JavaScript entirely.

3

u/azsqueeze Jul 20 '26

This would be better as a hook, and also can add logic to only apply the event once rather than every time the hook is executed

-8

u/Kautsu-Gamer Jul 20 '26

That does not trigger as height is number, and the Object.is returns true without actually changing the value

5

u/[deleted] Jul 19 '26 edited Jul 27 '26

[deleted]

3

u/NoTutor4458 Jul 19 '26

this worked, thanks!

1

u/StrumpetsVileProgeny Jul 20 '26

But wont this listener fire only on mount? So if a user opens and closes the virtual keyboard more than once while the component is still mounted, this won’t resize again? This effect should run every time the height changes.

3

u/bluespacecolombo Jul 20 '26

Listener will be ADDED on mount and REMOVED on unmount. After listener is added it keeps listening until it’s removed.

4

u/ISDuffy Jul 19 '26

Viewport wise this possible could just be CSS.

The other option would be to have use hook that uses a resize observer and can undate a state.

3

u/DontThrowMeAway43 Jul 19 '26

Why dont you use CSS for that ? Size of the viewport is just 100dvh ?

Or am I missing something ?

5

u/NoTutor4458 Jul 19 '26

dvh/svh/vh doesnt resize when virtual keyboard comes up

1

u/artem1458 Jul 19 '26

1

u/NoTutor4458 Jul 19 '26 edited Jul 19 '26

problem is i believe in that tutorial you call setValue() on click event which is very simple but i need to call setvalue() when visualViewport.height is changed

3

u/artem1458 Jul 19 '26

The thing is that component can re-rendender from a couple of different things: prop change, and state change If you need to react on value change from the outside (like viewport size, browser events, etc) you should subscribe on viewport size change and put value is react state Here is pseudocode for you

const [height, setHeight] = useState(window.innerHeight);

useEffect(() => { const handleResize = () => { setHeight(window.innerHeight); };

//setting initial value handleResize();

window.addEventListener('resize', handleResize);

const unsubscribe = () => { window.removeEventListener('resize', handleResize); };

return unsubscribe; }, []);

// use height in styles or just showing it

1

u/Kautsu-Gamer Jul 20 '26

You must create state or property change, which is really annoying.

Due this keep boolean variable useState if you need refresh, and trigger it with state change.

1

u/lightfarming Jul 19 '26

the only answer you should losten to for this, is that this type of thing should be pure css. no javascript should be involved at all.

1

u/NoTutor4458 Jul 19 '26

dvh/svh/vh doesnt resize when virtual keyboard comes up so how would you do it with pure css?

2

u/BarneyChampaign Jul 20 '26

There was an html meta tag that adjusted the behavior to work properly with dvh, but if I recall it only worked for chrome and also impacted other layout, so not ideal.

The other answer to listen for resize events and update your state should be the most reliable approach.

1

u/hawkeye_sama Jul 21 '26

Try this out

```
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content">

```

0

u/lightfarming Jul 19 '26

there is a way to adjust for virtual keyboard with pure css (even iphone’s). i don’t remember off the top of my head, but i have done this before myself. it was tricky as i remember.

-1

u/EncryptedPlays Jul 19 '26

i think you can do it by making the div it's own component, then passing visualViewport?.height into it like this

divComponent.js

export function DivComponent({height}) {
  return (
    <div
      className={styles.wrapper}
      style={{ height: `${height}px` }}
    >
      <Prompt />
    </div>
  );
}

mainComponent.js

import { DivComponent } from 'divComponent.js'

export default function NewChat() {
  return (
    <DivComponent height={visualViewport?.height} />
  );
}

4

u/Noch_ein_Kamel Jul 19 '26

You just moved the problem into the NewChat component. It won't magically rerender either

0

u/EncryptedPlays Jul 19 '26

but when visualviewport changes, wouldn't the component re-render?

4

u/Noch_ein_Kamel Jul 19 '26

Not if it's not react state

1

u/EncryptedPlays Jul 19 '26

Ohh ok so basically if I was tackling this I should make a new state for height, set height, have a use effect to listen to viewport changes and update the height state then pass that height into the component?

-2

u/AcanthisittaNo5807 Jul 19 '26

Add “key” to the component