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
lxsmnsyc4mo ago
do you have any example code
Дикий
Дикий4mo ago
html part or js?
lxsmnsyc
lxsmnsyc4mo ago
which ever code is related to your problem
Дикий
Дикий4mo ago
There's mostly js in there but it's very huge and complex
lxsmnsyc
lxsmnsyc4mo ago
then a repro would be great
Дикий
Дикий4mo ago
i can explain how it works
lxsmnsyc
lxsmnsyc4mo ago
I'm not sure an explanation would be helpful here. A repro helps demonstrate the issue better
Дикий
Дикий4mo 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
lxsmnsyc4mo ago
How are you updating props.users?
Дикий
Дикий4mo ago
What do you mean?
lxsmnsyc
lxsmnsyc4mo ago
like how are you updating it's signal
Дикий
Дикий4mo ago
in index.jsx I have
let [users, setUsers] = createSignal([]);
let [users, setUsers] = createSignal([]);
<Users users={users} />
<Users users={users} />
lxsmnsyc
lxsmnsyc4mo ago
yes, how are you updating the users
пипъ trombalny
usersJson = await axios.... //request to api setUsers(usersJson);
peerreynders
peerreynders4mo 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
REEEEE4mo ago
try setting {equals: false} option on the signal
let [users, setUsers] = createSignal([], {equals: false});
let [users, setUsers] = createSignal([], {equals: false});
Дикий
Дикий4mo ago
this doesn't working
REEEEE
REEEEE4mo ago
hmmm And what is under the <For> What are you displaying with the data?
Дикий
Дикий4mo ago
swiper slider
REEEEE
REEEEE4mo ago
Could you show a little bit of the code?
Дикий
Дикий4mo ago
No description
REEEEE
REEEEE4mo ago
Okay, and nothing is updated in the For? Is the Swiper component from a library?
пипъ trombalny
yes
REEEEE
REEEEE4mo 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
peerreynders4mo ago
Where does it list Swiper SolidJS? Found it Their landing page doesn't show it.
Дикий
Дикий4mo ago
?
REEEEE
REEEEE4mo 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())
})
Дикий
Дикий4mo ago
createeffect is not called
REEEEE
REEEEE4mo ago
so the data might not be getting updated Especially if you're using {equals: false} and it's still not calling the createEffect
Дикий
Дикий4mo ago
If I add an interval to the props.users() output, it will show that the data is being updated
REEEEE
REEEEE4mo ago
right, but we want the effect to do that on it's own. I think reactivity is being broken somewhere
peerreynders
peerreynders4mo ago
To me that would suggest that you are modifying the object but are not calling setUsers again.
Дикий
Дикий4mo ago
No description
No description
REEEEE
REEEEE4mo 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?
Дикий
Дикий4mo ago
i dont understand im just using props
REEEEE
REEEEE4mo 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
REEEEE4mo 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
REEEEE4mo 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
REEEEE4mo 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
REEEEE4mo ago
Do you get an error?
пипъ trombalny
second code repeats billion times
Дикий
Дикий4mo ago
no
REEEEE
REEEEE4mo ago
okay, what happens when it breaks?
Дикий
Дикий4mo ago
this swiper error like
REEEEE
REEEEE4mo ago
I see
Дикий
Дикий4mo ago
when somewhere is variable broken
пипъ trombalny
but without {equals: true} swiper working
Дикий
Дикий4mo ago
or something else
REEEEE
REEEEE4mo ago
this is okay, we can solve the problem from here or you could try using a store actually
Дикий
Дикий4mo ago
we just started porting the code over from next.js and it worked fine there
Maciek50322
Maciek503224mo ago
do you call this start inside createEffect?
пипъ trombalny
yes
Maciek50322
Maciek503224mo ago
that then causes infinite loop
Дикий
Дикий4mo ago
start(); called one time
Maciek50322
Maciek503224mo 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
Maciek503224mo 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)
Дикий
Дикий4mo ago
no only 1 time
Maciek50322
Maciek503224mo ago
oh ok
REEEEE
REEEEE4mo ago
I don't think there's a infinite loop,
Maciek50322
Maciek503224mo ago
So does it work now however you wanted?
пипъ trombalny
Before the addition of untrack there was an infinite loop
REEEEE
REEEEE4mo ago
oh okay
пипъ trombalny
no(
Maciek50322
Maciek503224mo ago
What doesn't work
пипъ trombalny
The problem described in the topic description is still active
Дикий
Дикий4mo ago
rendering a posts
Maciek50322
Maciek503224mo ago
with {equals: false} & untrack, do you still make request for new data?
Дикий
Дикий4mo ago
yes
Maciek50322
Maciek503224mo ago
is there another place in code that this request is made?
Дикий
Дикий4mo ago
No description
Дикий
Дикий4mo ago
yes
peerreynders
peerreynders4mo 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.
Дикий
Дикий4mo ago
?
No description
Maciek50322
Maciek503224mo 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?
Дикий
Дикий4mo ago
I'm sure this query returns different data
peerreynders
peerreynders4mo ago
Is this when the usersResponseToAdd code runs?
Дикий
Дикий4mo ago
oh sorry no if inserted directly into the function after the usersResponse line, it will not work
peerreynders
peerreynders4mo 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.
Дикий
Дикий4mo ago
I made a mistake in that screenshot and put the code in the wrong place. no
Maciek50322
Maciek503224mo ago
I'd try replacing whole onUserSwipe body with { setUsers({}) }, does swiper then disappears?
Дикий
Дикий4mo ago
yes
Maciek50322
Maciek503224mo ago
now leave setUsers({}) at the beggining of the function, and paste previous body after it does it works then? it shouldn't
Дикий
Дикий4mo ago
no
No description
Maciek50322
Maciek503224mo ago
ok start from original body again, now before setUsers(usersJson);, do setUsers({})
Дикий
Дикий4mo ago
it works but reloading realoding swiper
Maciek50322
Maciek503224mo ago
do you still have {equals: false}?
Дикий
Дикий4mo ago
yes
Maciek50322
Maciek503224mo ago
what do you mean reloading reloading swiper? infinite loop?
Дикий
Дикий4mo ago
I misspelled it's just that when he uploads new posts, the swiper reboots, so to speak.
Maciek50322
Maciek503224mo 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({})
Дикий
Дикий4mo ago
It's complicated because it's all tied to him. there's ids and a bunch of other things
Maciek50322
Maciek503224mo 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
Дикий
Дикий4mo ago
doesn't work without setusers
Maciek50322
Maciek503224mo ago
hmm I misspelled there, should be Object.keys(props.users().success), but if it compiled, you probably did it right
Дикий
Дикий4mo ago
nothing wait
Дикий
Дикий4mo ago
output
No description
Maciek50322
Maciek503224mo ago
what's this output of?
Дикий
Дикий4mo ago
No description
Maciek50322
Maciek503224mo ago
can you elaborate more? in devTools you see something that page doesn't display?
Дикий
Дикий4mo ago
no and another problem setUsers() reactivity trigger doesn't working