preact-render-to-string icon indicating copy to clipboard operation
preact-render-to-string copied to clipboard

Context and useState for inter-component state such as CSS for <head>

Open pauleveritt opened this issue 1 year ago • 0 comments

This is likely a basic misunderstanding, though I've read a lot of tickets and tried a lot of code.

I'm working on Preact as an 11ty template language. I'd like a way for subcomponents to add CSS to <head>, as well as some other uses of state during SSR.

preact-render-to-string has some support for context and hooks. I tried this:

import { createContext } from "preact";
import { useContext, useState } from "preact/hooks";

export const MyContext = createContext();

export function Child() {
  const { value, setValue } = useContext(MyContext);
  // Changing the state has no effect, neither here
  // in child nor in parent.
  setValue(33);
  return (
    <div>
      <p>Value in child: {value}</p>
    </div>
  );
}

export function App() {
  const [value, setValue] = useState(99);
  return (
    <MyContext.Provider value={{ value, setValue }}>
      <div>
        <Child />
        <p>Value in parent: {value}</p>
      </div>
    </MyContext.Provider>
  );
}

In a Vitest test:

it("should render", async () => {
  const app = <App/>;
  await renderToStringAsync(<App />);
  const result = await renderToStringAsync(app);
  expect(result).toContain("count is 33");
});

It still renders with the original 99. Do I need to trigger some lifecycle method? Render first with Preact, then render to a string? (I saw an experiment from @developit using undom.)

pauleveritt avatar Jul 01 '24 19:07 pauleveritt