#Data not updated props vs slot

7 messages · Page 1 of 1 (latest)

compact pelican
#

Hi all!
First of all, I’d like to congratulate the team and all the people involved in this project for the great job they are doing.

I’ve been exploring the framework over the weekend and there is a behavior that I can’t understand. I’m using the InvoiceStatus component to render the status, but after updating the status and reloading the page using navigate(); to get the updated data, only the data passed by the slot is updated, while the prop value remains the original one.

Could anyone provide me with any idea or reference to understand the mistake and a possible solution?

Thanks in advance.

weak hollow
compact pelican
#

Hey @weak hollow, thanks for the advice, I also simplified the example.

import { $, component$, Slot } from "@builder.io/qwik";
import { useNavigate, routeAction$, routeLoader$ } from "@builder.io/qwik-city";


const tasks: { name: string; done: boolean }[] = [
  { name: "learn Qwik", done: false },
  { name: "learn Prisma", done: false },
  { name: "learn Tailwind", done: false }
];

export const useTaskList = routeLoader$(async () => {
  return Promise.resolve(tasks);
});

export const useCompleteTaskAction = routeAction$((data) => {
  tasks.find(task => task.name === data.name)!.done = true;
});

export const Status = component$(({ done }: { done: boolean }) => {
  return <span style={{ margin: "5px" }}>
        Status: "<Slot />" {done ? "✅" : "❌"}
      </span>;
});

export default component$(() => {

  const tasks = useTaskList();
  const completeTaskAction = useCompleteTaskAction();
  const navigate = useNavigate();

  const completeTask = $(async ({ name }: { name: string }) => {
    await completeTaskAction.submit({ name });
    navigate();
  });

  return (
    <>
      <ul>
        {tasks.value.map((task) => (
          <li key={task.name}>
            {task.name}
            <Status done={task.done}>
              <span>{task.done ? "Done" : "To Do"}</span>
            </Status>
            {!task.done
              ? <button onClick$={() => completeTask({ name: task.name })}> Complete </button>
              : ""
            }
          </li>
        ))}
      </ul>
    </>
  );
});

Thanks in advance !

compact pelican
#

I had some time to test an with some modifications in the Status component, passing an object instead a boolean , the behaviour is the expected for me:

export const Status = component$(({ task }: { task: Task }) => {
  return <span style={{ margin: "5px" }}>
        Status: "<Slot />" {task.done ? "✅" : "❌"}
      </span>;
});

I also tried to add an unique key property in the Status component, although the parent <li> already has the mandatory key as a map element, to force, in some way, the rendering of the component, and it works.

  return (
    <>
      <ul>
        {tasks.value.map((task) => (
          <li key={task.name}>
            {task.name}
            <Status key={`${task.name} ${task.done}`} done={task.done}>
              <span>{task.done ? "Done" : "To Do"}</span>
            </Status>
            {!task.done && <button onClick$={() => completeTask({ name: task.name })}> Complete </button> }
          </li>
        ))}
      </ul>
    </>
  );
weak hollow
compact pelican
#

Yes, I solved it, but I don’t think it was a very elegant way. Thinking to put an extra ‘key’ attribute or pass properties with objects adds an extra effort and unexpected behavior for me. But I suppose that these types of peculiarities will improve in the next versions. Congratulations for the work, because the general experience is amazing.