denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.15k stars 619 forks source link

Conditional Island Children #2397

Closed mcgear closed 4 months ago

mcgear commented 4 months ago

I have a super simple island i am trying to use to showcase an issue i'm having in a more complex island. The issue seems to come down to this...

I have a simple island:

type ShellProps = {
  children: ComponentChildren;
  hide?: boolean;
} & JSX.HTMLAttributes<HTMLAnchorElement>;

export default function Shell(props: ShellProps) {
  typeof document !== 'undefined' && alert(props.value);

  const hide = useSignal(props.hide);

  if (props.hide) {
    setTimeout(() => {
      console.log('unhide');
      hide.value = false
    }, 2500);
  }

  return <>{hide ? '' : props.children}{hide}</>;
}

Which i then use in a page:

<Shell value="Shell 2" hide={true}>
    <Button>Hello</Button>
</Shell>

The alery goes off, and the 'unhide' console log occurs, however the Button (children) never display once the signal is changed. What am i doing wrong here?

Thanks for the help.

CAYdenberg commented 4 months ago

Does it work if you put the entire if (props.hide) { block into a useEffect?

marvinhagemeister commented 4 months ago

The problem is this line:

return <>{hide ? '' : props.children}{hide}</>;

Signals are objects or classes to be more specific. Both objects or classes are always cast to be truthy in JavaScript. To compare against the signal's value, use the .value property. I think that's what you meant to do.

  export default function Shell(props: ShellProps) {
    typeof document !== 'undefined' && alert(props.value);

    const hide = useSignal(props.hide);

    if (props.hide) {
      setTimeout(() => {
        console.log('unhide');
        hide.value = false
      }, 2500);
    }

-   return <>{hide ? '' : props.children}{hide}</>;
+   return <>{hide.value ? '' : props.children}{hide}</>;
  }