Svelte derived store returns incorrect value

738 Views Asked by At

I have a problem with derived store, which somehow returns an empty result even tho in the store is 1 record. The derived store depends on 2 writable stores: assignedAgentsIds (array of agent ids) and agents (map of agent entity). If I use both stores directly in a component, it works just fine, but when I use them in a derived store and try to combine them, I'm always getting empty array.

Here is my store code:

const createAssignedAgentsStore = () => {
    const assignedAgentIds = writable<string[]>([])
    const { subscribe, set, update } = assignedAgentIds

    const setAssignedAgentIds = (agentIds: string[]) => {
        set(agentIds)
    }

    const addAssignedAgentId = (agentId: string) => {
        update((agentIds) => [...agentIds, agentId])
    }

    return {
        subscribe,
        setAssignedAgentIds,
        addAssignedAgentId,
    }
}

export const assignedAgentIds = createAssignedAgentsStore()

export const assignedAgents = derived([assignedAgentIds, agents], ([$assignedAgentIds, $agents]): Agent[] => {
    const assignedAgentsArr: Agent[] = []

    for (const agentId of $assignedAgentIds) {
        const agent = $agents[agentId]
        if (agent) assignedAgentsArr.push(agent)
    }

    return assignedAgentsArr
})

I tried to debug both $assignedAgentIds and $agents inside derived store, it has correct values and if there is 1 id in assignedAgentsIds and 1 record with the same id in agents map, still when I use $assignedAgents store in component, I get empty array instead of an array with 1 entity.

Edit

In Svelte component, I had this code to show correct type of agents which was also using assignedAgents store:

let headerAgents: Agent[] = []

$: {
    let agentsArray = Object.values($agents)
    if ($assignedAgents.length > 0) {
        agentsArray = $assignedAgents
    }

    headerAgents = agentsArray.splice(0, 3)
}
2

There are 2 best solutions below

2
On BEST ANSWER

I was passing reference to the assignedAgents store in component and mutating the store with splice function. Solution is to not mutate store by using slice function.

This is code that works:

let headerAgents: Agent[] = []

$: {
    let agentsArray = Object.values($agents)
    if ($assignedAgents.length > 0) {
        agentsArray = $assignedAgents
    }

    headerAgents = agentsArray.slice(0, 3)
}
4
On

The code looked fine to me, so I just tried to run it and it worked. At least when the agents store is correctly in scope. Though it will throw if it isn't.

Full example:

<script>
    import { writable, derived } from 'svelte/store';

    const createAssignedAgentsStore = () => {
        const assignedAgentIds = writable([])
        const { subscribe, set, update } = assignedAgentIds

        const setAssignedAgentIds = (agentIds) => {
            set(agentIds)
        }

        const addAssignedAgentId = (agentId) => {
            update((agentIds) => [...agentIds, agentId])
        }

        return {
            subscribe,
            setAssignedAgentIds,
            addAssignedAgentId,
        }
    }

    const assignedAgentIds = createAssignedAgentsStore()
    const agents = writable({
        0: 'Joe',
        1: 'Jane',
        2: 'Steve',
    });

    const assignedAgents = derived(
        [assignedAgentIds, agents],
        ([$assignedAgentIds, $agents]) => {
            const assignedAgentsArr = []

            for (const agentId of $assignedAgentIds)
            {
                const agent = $agents[agentId]
                if (agent) assignedAgentsArr.push(agent)
            }

            return assignedAgentsArr
        }
    )

    assignedAgentIds.setAssignedAgentIds([1, 2]);
</script>

{#each $assignedAgents as agent}
    <p>{agent}</p>
{/each}

REPL

I suspect the issue is elsewhere.