1

My SolidJS component fetches a JSON object from a server. I can use the SolidJS For loop to process the result, but I cannot use the vanilla javascript filter function.

function YearSearch(props) {
  const [years] = createResource(() => server.fetchData("json/list-of-years"))
  return (
    <Show when={ years() }>
      <For each={ years() }>
        {(num, key) => 
          <p>This works... { num.name }</p>
        }
      </For>
    </Show>
  )
}

The code above works as expected, but the code below returns the error "years.filter is not a function".

function YearSearch(props) {
  const [years] = createResource(() => server.fetchData("json/list-of-years"))
  return (
    <Show when={ years() }>
      <For each={ years.filter(num => num.name.includes(searchString)) }>
        {(num, key) => 
          <p>This returns an error... { num.name }</p>
        }
      </For>
    </Show>
  )
}

Note: searchString is a SolidJS Signal set by an input field.

I believe this fails because years or years() is a custom SolidJS thing rather than a simple array.

So my question is: How do I convert years() into an array that can be filtered?

tchrist
  • 78,834
  • 30
  • 123
  • 180

1 Answers1

1

There is nothing special about arrays wrapped in a signal, they should work as expected of any array.

You need to invoke years inside For component to get the wrapped array. Make sure the resource callback returns an array.

If searchString is a signal, you need to invoke it too, otherwise filter callback looks for a function.

import { For, Match, Switch, createResource } from 'solid-js';
import { render } from 'solid-js/web';

const App = () => {
  const list = () => {
    return new Promise<Array<number>>((resolve) => {
      setTimeout(() => {
        resolve([1, 2, 3, 4, 5]);
      }, 500);
    });
  };

  const [data] = createResource(list);

  return (
    <Switch>
      <Match when={data.state === 'pending'}>Pending</Match>
      <Match when={data.state === 'errored'}>Error</Match>
      <Match when={data.state === 'ready'}>
        <For each={data()!.filter((el) => el > 3)}>
          {(item) => <div>{item}</div>}
        </For>
      </Match>
    </Switch>
  );
};

render(App, document.body);

Non null assertion is needed because typescript cannot infer the data inside a Show or a Switch components.

Live demo: https://playground.solidjs.com/anonymous/a35f9469-e0da-4e3c-b03e-f899637c8f43

snnsnn
  • 10,486
  • 4
  • 39
  • 44