when changing a dynamic variable that contains json <For> will not be re-rendered

I have a variable createsignal and it contains json and during actions on the page it receives data from the server and through the <For> element it should be displayed every time the variable is changed but it doesn't work what to do?
111 Replies
lxsmnsyc
lxsmnsyc9mo ago
do you have any example code
Дикий
ДикийOP9mo ago
html part or js?
lxsmnsyc
lxsmnsyc9mo ago
which ever code is related to your problem
Дикий
ДикийOP9mo ago
There's mostly js in there but it's very huge and complex
lxsmnsyc
lxsmnsyc9mo ago
then a repro would be great
Дикий
ДикийOP9mo ago
i can explain how it works
lxsmnsyc
lxsmnsyc9mo ago
I'm not sure an explanation would be helpful here. A repro helps demonstrate the issue better
Дикий
ДикийOP9mo ago
Our JS code produces JSON like this:
{
success: {
username123: {
posts: [{},{},{}]
}
}
}
{
success: {
username123: {
posts: [{},{},{}]
}
}
}
And when our code adds more posts to the posts list, or adds other users to JSON (example below), the For list is not re-rendered.
{
success: {
username123: {
posts: [{},{},{},{},{},{}]
},
cool_username: {
posts: [{},{}]
}
}
}
{
success: {
username123: {
posts: [{},{},{},{},{},{}]
},
cool_username: {
posts: [{},{}]
}
}
}
And here's the For code:
<For each={Object.keys(props.users().success)}>
<For each={Object.keys(props.users().success)}>
<For each={props.users().success[id].posts}>
<For each={props.users().success[id].posts}>
And there are no problems in the js code that generates the json
lxsmnsyc
lxsmnsyc9mo ago
How are you updating props.users?
Дикий
ДикийOP9mo ago
What do you mean?
lxsmnsyc
lxsmnsyc9mo ago
like how are you updating it's signal
Дикий
ДикийOP9mo ago
in index.jsx I have
let [users, setUsers] = createSignal([]);
let [users, setUsers] = createSignal([]);
<Users users={users} />
<Users users={users} />
lxsmnsyc
lxsmnsyc9mo ago
yes, how are you updating the users
пипъ trombalny
usersJson = await axios.... //request to api setUsers(usersJson);
peerreynders
peerreynders9mo ago
That's not how it works. You need to use setUsers to set a new value (object) which is referentially different from the old value.
пипъ trombalny
that's what we do.
REEEEE
REEEEE9mo ago
try setting {equals: false} option on the signal
let [users, setUsers] = createSignal([], {equals: false});
let [users, setUsers] = createSignal([], {equals: false});
Дикий
ДикийOP9mo ago
this doesn't working
REEEEE
REEEEE9mo ago
hmmm And what is under the <For> What are you displaying with the data?
Дикий
ДикийOP9mo ago
swiper slider
REEEEE
REEEEE9mo ago
Could you show a little bit of the code?
Дикий
ДикийOP9mo ago
No description
REEEEE
REEEEE9mo ago
Okay, and nothing is updated in the For? Is the Swiper component from a library?
пипъ trombalny
yes
REEEEE
REEEEE9mo ago
Which library?
пипъ trombalny
Swiper
Swiper - The Most Modern Mobile Touch Slider
Swiper is the most modern free mobile touch slider with hardware accelerated transitions and amazing native behavior.
peerreynders
peerreynders9mo ago
Where does it list Swiper SolidJS? Found it Their landing page doesn't show it.
Дикий
ДикийOP9mo ago
?
REEEEE
REEEEE9mo ago
I don't see any exact issues with the code for the For, could be something else 🤔 If you console log in an effect, do you get the updated data?
createEffect(() => {
console.log(props.users())
})
createEffect(() => {
console.log(props.users())
})
Дикий
ДикийOP9mo ago
createeffect is not called
REEEEE
REEEEE9mo ago
so the data might not be getting updated Especially if you're using {equals: false} and it's still not calling the createEffect
Дикий
ДикийOP9mo ago
If I add an interval to the props.users() output, it will show that the data is being updated
REEEEE
REEEEE9mo ago
right, but we want the effect to do that on it's own. I think reactivity is being broken somewhere
peerreynders
peerreynders9mo ago
To me that would suggest that you are modifying the object but are not calling setUsers again.
Дикий
ДикийOP9mo ago
No description
No description
REEEEE
REEEEE9mo ago
yeah that could be a possibility. Show a bit of the code of the axios request and calling setUsers does the <Users/> component destructure props (although it shouldn't matter here) or is using mergeProps?
Дикий
ДикийOP9mo ago
i dont understand im just using props
REEEEE
REEEEE9mo ago
okay I don't see any exact issues with your code. Could you show the code where you are calling setUsers
пипъ trombalny
const start = async () => {
const usersResponse = await getPosts(0, checkedUsers());
let checked = checkedUsers();
if (usersResponse) {
checked.push(
Number(
usersResponse.success[Object.keys(usersResponse.success)[0]].author_id
)
);

setCheckedUsers(checked);
setUsers(usersResponse);
setAllUsersId(
Object.keys(usersResponse.success).map((user) =>
Number(usersResponse.success[user].author_id)
)
);
}
};
const start = async () => {
const usersResponse = await getPosts(0, checkedUsers());
let checked = checkedUsers();
if (usersResponse) {
checked.push(
Number(
usersResponse.success[Object.keys(usersResponse.success)[0]].author_id
)
);

setCheckedUsers(checked);
setUsers(usersResponse);
setAllUsersId(
Object.keys(usersResponse.success).map((user) =>
Number(usersResponse.success[user].author_id)
)
);
}
};
REEEEE
REEEEE9mo ago
I actually see no issues 🤣 @lxsmnsyc 🤖 Do you see anything wrong here?
пипъ trombalny
const onUserSwipe = async (user) => {
setCurrentUser(user);
const currentPost = user.slides.filter((element) =>
element.className.endsWith("active")
)[0];
let checked = checkedUsers();
if (!checked.includes("" + currentPost.id)) {
setCurrentUser(currentPost.id);
checked.push(currentPost.id);
console.log(checked);
}
setCheckedUsers(checked);

const [usersStatic, checkedUsersStatic, allUsersIdStatic] = [
Object.keys(users().success),
checkedUsers(),
allUsersId(),
];
const difference = usersStatic.length - checkedUsersStatic.length;
let usersJson = users();
if (difference === 1) {
const usersResponseToAdd = await getPosts(0, allUsersIdStatic);
if (usersResponseToAdd) {
Object.keys(usersResponseToAdd.success).map(
(user) => (usersJson.success[user] = usersResponseToAdd.success[user])
);
setUsers(usersJson);
}
}
};
const onUserSwipe = async (user) => {
setCurrentUser(user);
const currentPost = user.slides.filter((element) =>
element.className.endsWith("active")
)[0];
let checked = checkedUsers();
if (!checked.includes("" + currentPost.id)) {
setCurrentUser(currentPost.id);
checked.push(currentPost.id);
console.log(checked);
}
setCheckedUsers(checked);

const [usersStatic, checkedUsersStatic, allUsersIdStatic] = [
Object.keys(users().success),
checkedUsers(),
allUsersId(),
];
const difference = usersStatic.length - checkedUsersStatic.length;
let usersJson = users();
if (difference === 1) {
const usersResponseToAdd = await getPosts(0, allUsersIdStatic);
if (usersResponseToAdd) {
Object.keys(usersResponseToAdd.success).map(
(user) => (usersJson.success[user] = usersResponseToAdd.success[user])
);
setUsers(usersJson);
}
}
};
const onUserHorizontalSwipe = async (user) => {
let json = checkedHorizontalPosts();
let usersStatic = users();
const slide = user.slides.filter((element) =>
element.classList.value.includes("active")
)[0];
let [author_id, id] = [
Number(slide?.id.split(" ")[1]),
Number(slide?.id.split(" ")[0]),
];
if (Object.keys(json).includes(String(author_id))) {
if (!json[author_id].includes(id)) {
json[author_id].push(id);
}
} else {
json[author_id] = [id];
}
setCheckedHorizontalPosts(json);

Object.keys(users().success).map(async (user) => {
if (users().success[user].author_id === author_id) {
const difference =
users().success[user].posts.length - json[author_id].length;

if (difference == 2) {
const postsByUser = await getUserPosts(
users().success[user].posts[users().success[user].posts.length - 1]
.id,
author_id
);

if (postsByUser) {
postsByUser.success.map((post) => {
usersStatic.success[user].posts.push(post);
});
}
}
}
});
setUsers(usersStatic);
};
const onUserHorizontalSwipe = async (user) => {
let json = checkedHorizontalPosts();
let usersStatic = users();
const slide = user.slides.filter((element) =>
element.classList.value.includes("active")
)[0];
let [author_id, id] = [
Number(slide?.id.split(" ")[1]),
Number(slide?.id.split(" ")[0]),
];
if (Object.keys(json).includes(String(author_id))) {
if (!json[author_id].includes(id)) {
json[author_id].push(id);
}
} else {
json[author_id] = [id];
}
setCheckedHorizontalPosts(json);

Object.keys(users().success).map(async (user) => {
if (users().success[user].author_id === author_id) {
const difference =
users().success[user].posts.length - json[author_id].length;

if (difference == 2) {
const postsByUser = await getUserPosts(
users().success[user].posts[users().success[user].posts.length - 1]
.id,
author_id
);

if (postsByUser) {
postsByUser.success.map((post) => {
usersStatic.success[user].posts.push(post);
});
}
}
}
});
setUsers(usersStatic);
};
REEEEE
REEEEE9mo ago
and it doesn't even work with {equals: false}? That's so weird.
пипъ trombalny
When we put this option, the code starts replaying a billion times or just breaks SwiperJS
REEEEE
REEEEE9mo ago
wait, that might be a good thing that means the signal is updating and the swiper is being updated There might be a loop somewhere causing it to keep replaying
пипъ trombalny
let [users, setUsers] = createSignal([], { equals: false });
let [checkedUsers, setCheckedUsers] = createSignal([]);
let [allUsersId, setAllUsersId] = createSignal([]);
let [checkedHorizontalPosts, setCheckedHorizontalPosts] = createSignal({});
let [currentUser, setCurrentUser] = createSignal();
let [users, setUsers] = createSignal([], { equals: false });
let [checkedUsers, setCheckedUsers] = createSignal([]);
let [allUsersId, setAllUsersId] = createSignal([]);
let [checkedHorizontalPosts, setCheckedHorizontalPosts] = createSignal({});
let [currentUser, setCurrentUser] = createSignal();
or
let [users, setUsers] = createSignal([], { equals: false });
let [checkedUsers, setCheckedUsers] = createSignal([], { equals: false });
let [allUsersId, setAllUsersId] = createSignal([], { equals: false });
let [checkedHorizontalPosts, setCheckedHorizontalPosts] = createSignal(
{},
{ equals: false }
);
let [currentUser, setCurrentUser] = createSignal();
let [users, setUsers] = createSignal([], { equals: false });
let [checkedUsers, setCheckedUsers] = createSignal([], { equals: false });
let [allUsersId, setAllUsersId] = createSignal([], { equals: false });
let [checkedHorizontalPosts, setCheckedHorizontalPosts] = createSignal(
{},
{ equals: false }
);
let [currentUser, setCurrentUser] = createSignal();
first code breaks swiperjs
REEEEE
REEEEE9mo ago
Do you get an error?
пипъ trombalny
second code repeats billion times
Дикий
ДикийOP9mo ago
no
REEEEE
REEEEE9mo ago
okay, what happens when it breaks?
Дикий
ДикийOP9mo ago
this swiper error like
REEEEE
REEEEE9mo ago
I see
Дикий
ДикийOP9mo ago
when somewhere is variable broken
пипъ trombalny
but without {equals: true} swiper working
Дикий
ДикийOP9mo ago
or something else
REEEEE
REEEEE9mo ago
this is okay, we can solve the problem from here or you could try using a store actually
Дикий
ДикийOP9mo ago
we just started porting the code over from next.js and it worked fine there
Maciek50322
Maciek503229mo ago
do you call this start inside createEffect?
пипъ trombalny
yes
Maciek50322
Maciek503229mo ago
that then causes infinite loop
Дикий
ДикийOP9mo ago
start(); called one time
Maciek50322
Maciek503229mo ago
yes, but reactivity tracks the checkedUsers() and then in the same place you do setCheckedUsers() then because you call setCheckedUsers(), any effect with checkedUsers() has to rerun there's untrack you wrap anything you don't want function to react inside it Also there's createResource check it out here https://docs.solidjs.com/reference/basic-reactivity/create-resource
пипъ trombalny
const start = async () => {
const usersResponse = await getPosts(0, untrack(checkedUsers));
let checked = untrack(checkedUsers);
if (usersResponse) {
checked.push(
String(
usersResponse.success[Object.keys(usersResponse.success)[0]].author_id
)
);

setCheckedUsers(checked);
setUsers(usersResponse);
setAllUsersId(
Object.keys(usersResponse.success).map((user) =>
Number(usersResponse.success[user].author_id)
)
);
}
};
const start = async () => {
const usersResponse = await getPosts(0, untrack(checkedUsers));
let checked = untrack(checkedUsers);
if (usersResponse) {
checked.push(
String(
usersResponse.success[Object.keys(usersResponse.success)[0]].author_id
)
);

setCheckedUsers(checked);
setUsers(usersResponse);
setAllUsersId(
Object.keys(usersResponse.success).map((user) =>
Number(usersResponse.success[user].author_id)
)
);
}
};
? i added untrack
Maciek50322
Maciek503229mo ago
yeah so that probably still doesn't work because you want start to be called when checkedUsers change?
пипъ trombalny
no, when the page starts(1 time)
Дикий
ДикийOP9mo ago
no only 1 time
Maciek50322
Maciek503229mo ago
oh ok
REEEEE
REEEEE9mo ago
I don't think there's a infinite loop,
Maciek50322
Maciek503229mo ago
So does it work now however you wanted?
пипъ trombalny
Before the addition of untrack there was an infinite loop
REEEEE
REEEEE9mo ago
oh okay
пипъ trombalny
no(
Maciek50322
Maciek503229mo ago
What doesn't work
пипъ trombalny
The problem described in the topic description is still active
Дикий
ДикийOP9mo ago
rendering a posts
Maciek50322
Maciek503229mo ago
with {equals: false} & untrack, do you still make request for new data?
Дикий
ДикийOP9mo ago
yes
Maciek50322
Maciek503229mo ago
is there another place in code that this request is made?
Дикий
ДикийOP9mo ago
No description
Дикий
ДикийOP9mo ago
yes
peerreynders
peerreynders9mo ago
Near where the signal is created
createEffect(() => {
users();
console.log('users()', performance.now());
)
createEffect(() => {
users();
console.log('users()', performance.now());
)
In the component
createEffect(() => {
props.users();
console.log('props.users()', performance.now());
)
createEffect(() => {
props.users();
console.log('props.users()', performance.now());
)
That should give you an idea whether they behave the same or reactivity is broken in between.
Дикий
ДикийOP9mo ago
?
No description
Maciek50322
Maciek503229mo ago
let allUsersIdStatic = Object.keys(users().success)
let usersJson = users();
...
const usersResponseToAdd = await getPosts(0, allUsersIdStatic);
if (usersResponseToAdd) {
Object.keys(usersResponseToAdd.success).map(
(user) => (usersJson.success[user] = usersResponseToAdd.success[user])
);
setUsers(usersJson);
}
let allUsersIdStatic = Object.keys(users().success)
let usersJson = users();
...
const usersResponseToAdd = await getPosts(0, allUsersIdStatic);
if (usersResponseToAdd) {
Object.keys(usersResponseToAdd.success).map(
(user) => (usersJson.success[user] = usersResponseToAdd.success[user])
);
setUsers(usersJson);
}
allUsersIdStatic & usersJson are keys of object & the object. Then you update usersJson by what request returned for all it's keys (allUsersIdStatic), that should not give usersJson any new values. Are you sure that this request gives you different data?
Дикий
ДикийOP9mo ago
I'm sure this query returns different data
peerreynders
peerreynders9mo ago
Is this when the usersResponseToAdd code runs?
Дикий
ДикийOP9mo ago
oh sorry no if inserted directly into the function after the usersResponse line, it will not work
peerreynders
peerreynders9mo ago
I'm asking whether the output was from running the start section of the code or from running the usersResponseToAdd section of the code.
Дикий
ДикийOP9mo ago
I made a mistake in that screenshot and put the code in the wrong place. no
Maciek50322
Maciek503229mo ago
I'd try replacing whole onUserSwipe body with { setUsers({}) }, does swiper then disappears?
Дикий
ДикийOP9mo ago
yes
Maciek50322
Maciek503229mo ago
now leave setUsers({}) at the beggining of the function, and paste previous body after it does it works then? it shouldn't
Дикий
ДикийOP9mo ago
no
No description
Maciek50322
Maciek503229mo ago
ok start from original body again, now before setUsers(usersJson);, do setUsers({})
Дикий
ДикийOP9mo ago
it works but reloading realoding swiper
Maciek50322
Maciek503229mo ago
do you still have {equals: false}?
Дикий
ДикийOP9mo ago
yes
Maciek50322
Maciek503229mo ago
what do you mean reloading reloading swiper? infinite loop?
Дикий
ДикийOP9mo ago
I misspelled it's just that when he uploads new posts, the swiper reboots, so to speak.
Maciek50322
Maciek503229mo ago
I can only now think that this swiper somehow isn't reactive to children can you try doing same things in jsx, the <For> and some text inside, all without swiper? and without setUsers({})
Дикий
ДикийOP9mo ago
It's complicated because it's all tied to him. there's ids and a bunch of other things
Maciek50322
Maciek503229mo ago
I want to know just something like that:
<For each={Object.keys(props.users()).success}>
{(id) => <div>{props.users().success[id].author_id}</div>}
</For>
<For each={Object.keys(props.users()).success}>
{(id) => <div>{props.users().success[id].author_id}</div>}
</For>
if that works WITHOUT setUsers({}), and WITH {equals: false}, just thow it somewhere next to swiper
Дикий
ДикийOP9mo ago
doesn't work without setusers
Maciek50322
Maciek503229mo ago
hmm I misspelled there, should be Object.keys(props.users().success), but if it compiled, you probably did it right
Дикий
ДикийOP9mo ago
nothing wait
Дикий
ДикийOP9mo ago
output
No description
Maciek50322
Maciek503229mo ago
what's this output of?
Дикий
ДикийOP9mo ago
No description
Maciek50322
Maciek503229mo ago
can you elaborate more? in devTools you see something that page doesn't display?
Дикий
ДикийOP9mo ago
no and another problem setUsers() reactivity trigger doesn't working
Want results from more Discord servers?
Add your server