Search code examples
solid-js

Using a component and passing down a signal doesn't cause re-render


I've currently got a component to make life easier when making selects. My issue however is that whenever I reference a signal, it doesn't rerender that component when I'm setting it in createEffect.

Below is the Select component:

interface SelectProps {
  onChange?: (value: string) => void;
  size: SelectSize;
  options: string[];
  placeHolder?: string;
}

export enum SelectSize {
  Small = "w-[100px]",
  Medium = "w-[200px]",
  Large = "w-[300px]",
  XLarge = "w-[400px]",
}

export default function Select({
  onChange,
  size,
  options,
  placeHolder,
}: SelectProps) {
  const renderOptions = () => {
    return options.map((t) => <option value={t}>{t}</option>);
  };
  return (
    <select
      class={`bg-gray-50 border border-gray-300 text-gray-900 
      text-sm rounded-lg ${size} focus:ring-blue-500 focus:border-blue-500
       block  p-2.5  
       `}
      name="subtask"
      id="subtasks"
      onChange={(event) => {
        onChange?.(event.target.value);
      }}
    >
      {placeHolder ? (
        <option value={undefined} selected={true}>
          {placeHolder}
        </option>
      ) : undefined}
      {renderOptions()}
    </select>
  );
}

And it's being used on this page:

import { useLocation, useNavigate } from "@solidjs/router";
import NavBar from "../components/NavBar";
import { createEffect, createMemo, createSignal } from "solid-js";

import {
  WorkType,
  getSubTasks,
  work,
} from "../Api";

import Label from "../components/Label";

import Select, { SelectSize } from "../components/Select";

export default function AddWork() {
  const activeWork = (useLocation<work>().state as work) ?? undefined;
  const [work] = createSignal<work | undefined>(activeWork);
  const [subtask, setSubtask] = createSignal<string>("");
  const [subtasks, setSubTasks] = createSignal<string[]>([]);
  
  createEffect(() => {
    async function fetchSubTasks() {
      const workHolder = work();
      setSubTasks(await getSubTasks(workHolder.work_type))
    }
    
    fetchSubTasks();
  });
 

  return (
    <div class="space-x-0.5 flex justify-center m-20">
        <div class="flex flex-col items-center space-y-4">
          <Label text="Choose a subtask:" />
          <Select
            size={SelectSize.Medium}
            onChange={(value) => {
              setSubtask(value);
            }}
            options={subtasks()}
            placeHolder="Select a SubTask"
          />     
        </div>
    </div>
  );
}

Solution

  • Destructuring props will cause losing reactivity because you would be extracting reactive values into static variables. Components and effects need to read a signal in order to subscribe it.