Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When navigating using SPA web components rerender multiple times #550

Closed
AlbertSabate opened this issue Oct 14, 2024 · 3 comments · Fixed by #620
Closed

When navigating using SPA web components rerender multiple times #550

AlbertSabate opened this issue Oct 14, 2024 · 3 comments · Fixed by #620
Labels
bug Something isn't working render spa navigation

Comments

@AlbertSabate
Copy link
Collaborator

AlbertSabate commented Oct 14, 2024

Describe the bug
When you load a page for first time web components are rendering properly. once on the server and rehydrates on client.
When you are navigating using SPA to a page which is using web components, this will do multiple rerender.

To Reproduce
Navigate using SPA to a page with web components and add a console.log()

Expected behavior
Only 1 render or at most 1 render. No rerender expected as no user action has been triggered. Also, should rerender using signals, not the whole thing.

Screen recording
https://github.com/user-attachments/assets/81f33881-0e4e-4f6b-aa1c-13c2d1494948

As a consequence self.attachInternals() throw an error. Everything works as expected, but it should not rerender that many times, and not the whole component.

Code I used:

import type { WebContext } from 'brisa';

export interface InputProps {
  name: string;
  options: { key: string; value: string; selected?: boolean }[];
  id?: string;
  title?: string;
  labelClass?: string;
  inputClass?: string;
  placeholder?: string;
  value?: string;
  required?: boolean;
}

export default function FormMultiple(
  {
    name,
    options,
    title = '',
    id = '',
    inputClass = '',
    labelClass = '',
    value = '',
    required = false,
  }: InputProps,
  { self, derived }: WebContext,
) {
  console.log('rendering');
  const internals = self.attachInternals();
  const optionsWithSelected = derived(() => {
    return options.map((option) => ({
      ...option,
      selected: option.selected ?? false,
    }));
  });

  function onClickEvent(e: JSX.TargetedEvent<HTMLDivElement>) {
    optionsWithSelected.value = [
      ...optionsWithSelected.value.map((option) => ({
        ...option,
        selected:
          option.key === e.currentTarget.dataset.value
            ? !option.selected
            : option.selected,
      })),
    ];

    internals.setFormValue(
      JSON.stringify(
        optionsWithSelected.value
          .filter((option) => option.selected)
          .map((option) => option.key),
      ),
    );
  }

  return (
    <>
      {title ? (
        <label
          class={`block mb-1 text-sm ${labelClass}`.trim()}
          for={id ?? name}
        >
          {title}
        </label>
      ) : null}
      <div
        id={id ?? name}
        class={`flex flex-col gap-4 p-4 rounded text-black bg-background-light dark:text-white dark:bg-background-dark focus:outline-primary ${inputClass}`.trim()}
        value={value}
        required={required}
      >
        {optionsWithSelected.value.map((option) => (
          <div
            key={`${id ?? name}-${option.key}`}
            data-value={option.key}
            class={`cursor-pointer rounded p-4 border border-accent-light dark:border-accent-dark hover:bg-accent-light dark:hover:bg-accent-dark ${option.selected ? 'bg-secondary hover:bg-secondary' : ''}`.trim()}
            onClick={onClickEvent}
            onKeyDown={(e) => {
              e.preventDefault();
            }}
          >
            {option.value}
          </div>
        ))}
      </div>
    </>
  );
}
@AlbertSabate AlbertSabate added bug Something isn't working render spa navigation labels Oct 14, 2024
@aralroca
Copy link
Collaborator

It will have to be investigated why it happens. It should not make a second rerender when loading the page.

@aralroca
Copy link
Collaborator

aralroca commented Oct 29, 2024

I hope this whatwg/dom#1255 will be implemented in the platform, we will avoid all these diffing issues. Demo: https://state-preserving-atomic-move.glitch.me/?scenario=iframe (you need to activate the chrome flag)

@aralroca
Copy link
Collaborator

The re-render happens after this line of the diffing algorithm: https://github.com/aralroca/diff-dom-streaming/blob/0169dc1c9315099f340f7d60599e9fecf201eaca/src/index.ts#L183 I need to investigate more, what I find strange that an appendChild can do is to dismount and mount an existing web component in the DOM tree. But this re-render happens after an appendChild...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working render spa navigation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants