Search code examples
javascripttypescriptjsxtsxsolid-js

How to filter children composed of custom components in Solid JS?


I would like to create a simple scene switcher for my personal application. I figured I could create a custom component SceneSwitcher and inside this component, I could add scenes that will be rendered. Example:

<SceneSwitcher>
    <LoadingScene />
    <AppScene />
    <LoginScene />
</SceneSwitcher>

SceneSwitcher.tsx

export default function SceneSwitcher() {
    const [scene, setScene] = createSignal("");

    ...

    return (
        <>
            {props.children.find(e => e.id === scene()) ?? <div></div>}
        </>
    );
}

But props.children.find always returns undefined even when the value of scene() matches one of the IDs.

IDs on Scenes: LoadingScene.tsx

export default function LoadingScene() {
    ...
    return (
        <div id="loading">
            <h1>Loading content...</h1>
        </div>
    );
}

Note: I picked up a component-style framework just a few days ago (although I have been programming websites in vanilla js for 4 years now). What I wanted to say is, that this project is for me to learn component-style frameworks in a more practical way and the implementation can be different if there is a better way to solve this problem.


Solution

  • Lets see the requirements first:

    1. You need to track the active scene, so we use a signal for it.
    2. Establish a way to change the active scene, we use a list of scene names with event handlers that updates the active scene.
    3. A filter to filter the scenes based on their names, if they are active or not, and for this task we use Switch/Match components.
    const App = () => {
      const [active, setActive] = createSignal('loading');
    
      return (
        <div>
          <ul>
            <li onClick={() => setActive('loading')}>Loading</li>
            <li onClick={() => setActive('app')}>App</li>
            <li onClick={() => setActive('login')}>Login</li>
          </ul>
          <Switch>
            <Match when={active() === 'loading'}>
              <Loading />
            </Match>
            <Match when={active() === 'app'}>
              <App />
            </Match>
            <Match when={active() === 'login'}>
              <Login />
            </Match>
          </Switch>
        </div>
      );
    };
    

    You can use a router for what you are looking for. Url or pathname will be your way of tracking the active scene, navigation will be the the way of changing the active scene. Route component will the way to associate components with a path.

    https://github.com/solidjs/solid-router