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

Bad state isolation between components #4192

Closed
1 task
aventez opened this issue Nov 6, 2023 · 1 comment
Closed
1 task

Bad state isolation between components #4192

aventez opened this issue Nov 6, 2023 · 1 comment

Comments

@aventez
Copy link

aventez commented Nov 6, 2023

  • Check if updating to the latest Preact version resolves the issue

Describe the bug
Imagine we have an array with components we should render:

const [componentsToRender, setComponentsToRender] = useState([]);

onEvent('componentsReceived', (components) => {
   setComponentsToRender(components);
   // [Component1, Component2];
}

We render them like that:

{componentsToRender .map((page, index) => (
  <div key={index}>
    {page()}
  </div>
))}

Now, if we have 2 components - Component1, Component2;

Component1.ts

const [username, setUsername] = useState('')

/* all rest logic here */

<Form>
   <Input id="username" onChange={handleOnChange} value={username} />
   <Button onClick="handleSubmit">
</Form>

Now - we are closing Component1 with last username - let's say XYZ. Normally - it should be removed by some GC.

We are going further, and opening Component2, which should be completely independent from Component1.

Component2.ts

export default function SecondComponent() {
    const [myState, setMyState] = useState('TEST STRING');
    console.log(myState); // it is XYZ, from Component1 state.

As you can see - a tricky thing happens, as I am getting "XYZ" despite it should be TEST STRING. Also it works in second direction. If I will change state in Component2 and render Component1 again; input #username takes the value from Component2 state.

If I render these pages like that:

{pages.map((page) => {
          const PageComponent = page;
          return <PageComponent />;
        })}

Nothing wrong happens; state is isolated properly for component scope.

To Reproduce
Described above

@rschristian
Copy link
Member

This is the correct behavior from the framework's perspective -- you should never invoke components directly (page()), they expect (and need to be) called from the context of the framework.

const App = () => <div>foo</div>;

// DON'T: Invoking components directly breaks hooks and update ordering:
render(App(), rootElement); // ERROR
render(App, rootElement); // ERROR

// DO: Passing components using h() or JSX allows Preact to render correctly:
render(h(App), rootElement); // success
render(<App />, rootElement); // success

https://preactjs.com/guide/v10/api-reference#render

@rschristian rschristian closed this as not planned Won't fix, can't repro, duplicate, stale Nov 6, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants