adithyasource / clear

simple and lightweight game launcher
https://clear.adithya.zip
The Unlicense
35 stars 1 forks source link

Use context instead of global signals #5

Closed jer3m01 closed 2 months ago

jer3m01 commented 3 months ago

Instead of writing your signals in a file and importing all of them (including setting defaults in App.jsx) create a context and a provider to handle defaults.

Instead of:

// Signals.js
...
export const [showSideBar, setShowSideBar] = createSignal(true);
export const [roundedBorders, setRoundedBorders] = createSignal(true);
export const [gameTitle, setGameTitle] = createSignal(true);
export const [folderTitle, setFolderTitle] = createSignal(true);
export const [quitAfterOpen, setQuitAfterOpen] = createSignal(true);
export const [fontName, setFontName] = createSignal("sans serif");
...

create a context:

// global-context.js
const GlobalContext= createContext();

export function useGlobalContext() {
  const context = useContext(GlobalContext);

  if (context === undefined) {
    throw new Error(
        "[clear]: `useGlobalContext` must be used within a `GlobalContextProvider` component",
    );
  }

  return context;
}

export function GlobalContextProvider(props) {
  // Handle all defaults here
  const [showSideBar, setShowSideBar] = createSignal(libraryData().userSettings.showSideBar ?? true);
  const [roundedBorders, setRoundedBorders] = createSignal(libraryData().userSettings.roundedBorders ?? true);
  ...

  // side note:
  libraryData().userSettings.showSideBar ?? true
  // is a shorthand for:
  libraryData().userSettings.showSideBar == undefined
      ? true
      : libraryData().userSettings.showSideBar;

  // same for:
  libraryData().userSettings.roundedBorders ?? true
  // is short for:
  if (
    libraryData().userSettings.roundedBorders == undefined ||
    libraryData().userSettings.roundedBorders == true
  ) {
    true
  } else {
    false
  }
  // end of note

  const context = {
    showSideBar, 
    setShowSideBar,
    ...
  };

  return (
    <GlobalContext.Provider value={context}>
      {props.children}
    </GlobalContext.Provider>
  );
}

and in index.jsx:

render(() => <GlobaContextProvider><App /></GlobaContextProvider>, document.getElementById("root"));

Then in any component you can use:


function ExampleComponent() {
  const context = useGlobalContext();

  context.showSideBar(); // => boolean
  context.setShowSideBar(true);
}

For a concrete example you can checkout these files from Kobalte: https://github.com/kobaltedev/kobalte/blob/main/packages/core/src/dialog/dialog-context.tsx https://github.com/kobaltedev/kobalte/blob/main/packages/core/src/dialog/dialog-root.tsx

Solid docs: https://docs.solidjs.com/concepts/context https://docs.solidjs.com/reference/component-apis/create-context

Writing a follow up separate issue #6 for better state management using a store. Also checkout #7 for a better storage interface.

adithyasource commented 2 months ago

Thank you so much for the feedback, it's been implemented in bd05d83 and has helped clean up the code and made it much easier to understand!