Next.js Discord

Discord Forum

Image source changes unexpectedly when using ternary operator

Unanswered
Asian black bear posted this in #help-forum
Open in Discord
Asian black bearOP
In next 14 app router, image tag is imported from next/image and this is in client component.

<Image
src={
isOpen === true || (isOpen === null && width > 960)
? /logo_horizontal.png
: '/logo_icon.png'
}
loading="eager"
alt="logo"
fill
/>

when i reload the page even though the conditions in if statement are not changed (it stays true i can see it in console log) the false statement is executed before unmounting ie '/logo_icon.png'. i dont see any logs of condition being false but i see '/logo_icon.png' image before unmount why does this happen?

is there better way to handle this ?

18 Replies

Instead of conditionally setting the source, have two images components and conditionally render the correct one.

Also don't use loading="eager" instead use priority to eagerly preload important images above the fold.
@Plague Instead of conditionally setting the source, have two images components and conditionally render the correct one. Also don't use loading="eager" instead use `priority` to eagerly preload important images above the fold.
Asian black bearOP
have two images components and conditionally render the correct one.
implemented this but still facing same issue.
 {isOpen === true || (isOpen === null && width > 960) ? (
          <Image src="/logo_horizontal.png" priority alt="logo" fill />
  ) : (
          <Image src="/logo_icon.png" priority alt="logo" fill />
  )}


some additional info,
isOpen is a state and width is my viewport width i am getting from a hook.
i have log of the same condition which never logs false in console
Can isOpen only be true, false, or null?
Asian black bearOP
something to note about width state
it return 0 when typeof window === undifined ie when it renders on server.
but that should not be a problem because window will always be defined when it runs on browser right ?
@Plague Can `isOpen` only be true, false, or null?
Asian black bearOP
yes
type of isOpen is boolean | null
simplify the condition to:
{isOpen || width > 960 ? (
          <Image src="/logo_horizontal.png" priority alt="logo" fill />
  ) : (
          <Image src="/logo_icon.png" priority alt="logo" fill />
  )}


Also which value are you expecting? the horizontal one? Log the width value
@Plague simplify the condition to: {isOpen || width > 960 ? ( <Image src="/logo_horizontal.png" priority alt="logo" fill /> ) : ( <Image src="/logo_icon.png" priority alt="logo" fill /> )} Also which value are you expecting? the horizontal one? Log the width value
Asian black bearOP
yes i expecting horizontal logo (true statement)
This is the sequence of things happening
1) is see /logo_icon.png nothing on the log
2) loading.tsx file in my root folder renders
3) expected image /logo_horizontal.png renders and i get width = 1366 , condition is true in log
so ig the real question is why i see the component twice one before loading.tsx and once after it. After loading it rendres correctly
Okay so you are getting the end result, but there is some mismatch between the client-side JS hydrating and the initial server-rendered result
@Asian black bear so ig the real question is why i see the component twice one before `loading.tsx` and once after it. After loading it rendres correctly
Hydration is why, I ran into this situation earlier and it's why from now I'll stick to CSS for media queries rather than client-side JS since it is available on the server and will give me the correct result at all points of the render.
You have three options afaik:
1. Ignore it and accept the time it takes for the component to hydrate
2. remove the conditional JS in favor of CSS media queries to render the appropriate result (Recommended for most cases)
3. disable SSR for the component by dynamically importing it using next/dynamic
Asian black bearOP
i cannot do it with just media query because, it only depends on the viewport width initially later it depends on the state isOpen, (it is expandable sidebar ), option 3 sounds good will try that
thanks for your time, appreciate it
@Asian black bear thanks for your time, appreciate it
No problem, so it's an expandable sidebar that is closed by default? If so, then yeah option 3 is ideal it seems.
@Plague No problem, so it's an expandable sidebar that is closed by default? If so, then yeah option 3 is ideal it seems.
Asian black bearOP
by default if it is closed or open depends on viewport width
@Asian black bear by default if it is closed or open depends on viewport width
Okay, there is one downside that comes with disabling SSR and that's SEO for that component, if that sidebar contains navigation it may be important to optimize SEO for that component. Just something to consider if it is important to you.