Store update produces error "current is undefined"

I'm creating the example in the doc and getting the error
Uncaught TypeError: current is undefined
updatePath dev.js:217
...
setStore dev.js:247
...
Uncaught TypeError: current is undefined
updatePath dev.js:217
...
setStore dev.js:247
...
function App() {
const [store, setStore] = createStore({
userCount: 3,
users: [
{
id: 0,
username: "felix909",
location: "England ",
loggedIn: true,
},
{
id: 1,
username: "tracy634",
location: "Canada",
loggedIn: true,
},
{
id: 2,
username: "johny123",
location: "India",
loggedIn: true,
},
],
});

const logOutUser = () => {
setStore([0, 2], (user) => user.loggedIn, false);
};

return (
...
<button onClick={logOutUser}>Log out Tracy & Johnny</button>
...
)

}
function App() {
const [store, setStore] = createStore({
userCount: 3,
users: [
{
id: 0,
username: "felix909",
location: "England ",
loggedIn: true,
},
{
id: 1,
username: "tracy634",
location: "Canada",
loggedIn: true,
},
{
id: 2,
username: "johny123",
location: "India",
loggedIn: true,
},
],
});

const logOutUser = () => {
setStore([0, 2], (user) => user.loggedIn, false);
};

return (
...
<button onClick={logOutUser}>Log out Tracy & Johnny</button>
...
)

}
26 Replies
peerreynders
peerreynders2mo ago
The first key ([0,2]) of the path is specified as indices but the only valid keys are userCount and users. Perhaps you mean: “Log out users at index 1 and 2”
const logOutUser = () => {
setStore('users', [1, 2], 'loggedIn', false);
};
const logOutUser = () => {
setStore('users', [1, 2], 'loggedIn', false);
};
or
const logOutUser = () => {
setStore(
'users',
[1, 2],
produce((user) => (user.loggedIn = false))
);
};
const logOutUser = () => {
setStore(
'users',
[1, 2],
produce((user) => (user.loggedIn = false))
);
};
or “Log out loggedIn users”
const logOutUser = () => {
setStore('users', (user) => user.loggedIn, 'loggedIn', false);
};
const logOutUser = () => {
setStore('users', (user) => user.loggedIn, 'loggedIn', false);
};
zulu
zulu2mo ago
does this work for 0 and 2 ?
peerreynders
peerreynders2mo ago
It should (meaning 0 through 2; i.e. a range); I was going by "Log out Tracy & Johnny". For range:
const logOutUser = () => {
setStore('users', { from: 0, to: 2 }, 'loggedIn', false);
};
const logOutUser = () => {
setStore('users', { from: 0, to: 2 }, 'loggedIn', false);
};
zulu
zulu2mo ago
I guess your code will update the correct users based on the button text but what if you wanted felix[0] and johny[2] like you said [0,2] will mean all three 0..2 I am assuming inclusive edit: The docs was misleading, it gave me the impression that [0,2] was actually the range of 0 to 2 which in fact it is a list of all the keys to update Thanks @ryansolid for the reality check
ryansolid
ryansolid2mo ago
[0, 2] should be indexes 0 and 2 if you want to do 0 to 2 there is an object form for that
ryansolid
ryansolid2mo ago
GitHub
solid/packages/solid/store/src/store.ts at main · solidjs/solid
A declarative, efficient, and flexible JavaScript library for building user interfaces. - solidjs/solid
zulu
zulu2mo ago
ok so the docs might have thrown me off
zulu
zulu2mo ago
yep, thanks for the clarification I have seen the object form, and thought it was just an alternative to range with the addition of by
peerreynders
peerreynders2mo ago
I was going to suggest:
const logOutUser = () => {
setStore('users', (_user, i) => [0,2].includes(i), 'loggedIn', false);
};
const logOutUser = () => {
setStore('users', (_user, i) => [0,2].includes(i), 'loggedIn', false);
};
which does work.
zulu
zulu2mo ago
nice. filtering approach. less optimal, but good to have
Carl (klequis)
Carl (klequis)OP2mo ago
Thank you, the first one. The doc has:
setStore([0,2], (user) => user.loggedIn, false);
setStore([0,2], (user) => user.loggedIn, false);
It's an image from Eraser I can't edit. I'll open an issue. I wanted to see how to use a function as in the doc example. This makes a nice toggle.
setStore("users", [0,2], (user) => ({ loggedIn: !user.loggedIn}))
setStore("users", [0,2], (user) => ({ loggedIn: !user.loggedIn}))
peerreynders
peerreynders2mo ago
Alternately
const logOutUser = () => {
setStore('users', [0,2], 'loggedIn', (loggedIn) => !loggedIn);
};
const logOutUser = () => {
setStore('users', [0,2], 'loggedIn', (loggedIn) => !loggedIn);
};
… seems more fine-grained.
Carl (klequis)
Carl (klequis)OP2mo ago
Nice! Not understanding the source code for this (I did peek), it looks a bit magical that the loggedIn key is found, but it's a really nice feature.
zulu
zulu2mo ago
it traverse the path when it gets to the function it pass it the value and set back what is returned
Carl (klequis)
Carl (klequis)OP2mo ago
The doc seems to be trying to show and example of filtering:
"Alternatively, you can use filtering functions to access keys based on dynamic conditions or specific rules."
I haven't figured that out yet. Here is the example: AS @zulu points out, it is setStore('key', 'key', '...key', value). I could change the function for value to set loggedIn=true if it is false, but I wouldn't call that "filtering".
No description
ryansolid
ryansolid2mo ago
It is for filtering lists generally.. but since you already set an index I'm not sure that works.. it might still I suppose It's for.. set all users with loggedIn true.. to false..
setState(user => user.loggedIn, "loggedIn", false)
setState(user => user.loggedIn, "loggedIn", false)
Or some other condition.
peerreynders
peerreynders2mo ago
Filtering on an array happens here: https://github.com/solidjs/solid/blob/41fa6c14b4bf71eed593303cd63b32d53e3515e9/packages/solid/store/src/store.ts#L283-L288 note that for the recursive update the current part does not change but instead an exact index is pre-pended (replacing the dynamic filter function in a way) to the path.
GitHub
solid/packages/solid/store/src/store.ts at 41fa6c14b4bf71eed593303c...
A declarative, efficient, and flexible JavaScript library for building user interfaces. - solidjs/solid
zulu
zulu2mo ago
is this incorrect assumptions
setStore(
"users",

[0, 2, 3], // for users at index 0, 2, 3
["ids"], // step into 'ids'
(a, idx) => {
// for each isEven id return true in the filter
return idx % 2 == 0;
},
(v) => {
// increment the value at isEvent index by 1
return v + 1;
},
);
setStore(
"users",

[0, 2, 3], // for users at index 0, 2, 3
["ids"], // step into 'ids'
(a, idx) => {
// for each isEven id return true in the filter
return idx % 2 == 0;
},
(v) => {
// increment the value at isEvent index by 1
return v + 1;
},
);
https://playground.solidjs.com/anonymous/3a990d42-d2f4-4592-914f-dc8bdfe98db6 ( it only works on the object at index 0 )
peerreynders
peerreynders2mo ago
( it only works on the object at index 0 )
Check again; 0 and 2 are hit, 3 doesn't exist and ["ids"] could just be "ids".
zulu
zulu2mo ago
oh whoops let me check could have sworn it didn't work, ok the assumption is correct https://playground.solidjs.com/anonymous/75b53d30-ce97-4a7a-9cba-b392f09ec6e8 thanks for the heads up
Carl (klequis)
Carl (klequis)OP2mo ago
These two work:
setState("users", (user) => user.loggedIn, "loggedIn", false);

setState("users", (user) => user.id < 2, "loggedIn", true);
setState("users", (user) => user.loggedIn, "loggedIn", false);

setState("users", (user) => user.id < 2, "loggedIn", true);
zulu
zulu2mo ago
the 1st one mean log out any user that is logged in the 2nd mean: log in users with id less than 2
Carl (klequis)
Carl (klequis)OP2mo ago
I wondered if the function had to be a filter and it appears it must be because this doesn't work:
setStore("users", 0, () => "loggedIn", true);
setStore("users", 0, () => "loggedIn", true);
I'm still curious to examine more but it is late so tomorrow.
zulu
zulu2mo ago
() => "loggedIn" this will mean true for the filter function my assumption it will just replace your user object at index 0 with the true value but because the object is not iterable then something unexpected will happen This might summarize it: Last Argument ( value setter part ) #### The last argument is always the value or the setter function path arguments #### all arguments before the last argument are part of the path traversal logic #### a path argument can be a key, array of keys, function, object{from,to,by} #### if it is a key it will drill down one level #### if it is a array of keys it will iterate over each key, and apply/drill down with the next argument logic for each #### if it is a function it is used as a filter for the level ( so only use it for iterable level ) #### object with from,to,by is similar to the list of keys but allow range shortcut
Carl (klequis)
Carl (klequis)OP2mo ago
Super helpful pointing out the code. Thank you!

Did you find this page helpful?