S
SolidJS•2y ago
Nin

Rerender child component with updated props

I've built a pagination component that takes a prop called totalPages, I've created a signal for this as I only know the totalPages once my createResource is done loading. However, the child component does not rerender when totalPages is updated. How do I make the component update itself? Parent Code
const [totalPages, setTotalPages] = createSignal(0)
const [totalPages, setTotalPages] = createSignal(0)
<Pagination
pagesBuffer={5}
totalPages={totalPages()}
onChange={(index) => {
setCurrentPage(index + 1)
refetch()
}
}
/>
<Pagination
pagesBuffer={5}
totalPages={totalPages()}
onChange={(index) => {
setCurrentPage(index + 1)
refetch()
}
}
/>
11 Replies
lxsmnsyc
lxsmnsyc•2y ago
Most likely you are either: - Destructuring totalPages - You are accessing totalPages non-reactively (which applies to destructuring too)
Nin
Nin•2y ago
I have a paginationLogic function that returns the totalPages destructured (I think, very new to all this still)
return {
cursor,
totalPages: props.totalPages,
goNext,
goPrev,
goPage,
}
return {
cursor,
totalPages: props.totalPages,
goNext,
goPrev,
goPage,
}
Which is then taken into the pagination component like so
const { cursor, totalPages, goNext, goPrev, goPage } = paginationLogic(props)
const { cursor, totalPages, goNext, goPrev, goPage } = paginationLogic(props)
So I think I understand what you're saying but what to do with it is a whole other thing 😄
lxsmnsyc
lxsmnsyc•2y ago
If your background is React, the explanation here is that Solid only ever renders once. It doesn't know the concept of re-rendering unlike React, although it can re-render, we highly discourage doing it To fix this, first we must not do one of the things we don't encourage: destructuring Most likely, this line:
const { cursor, totalPages, goNext, goPrev, goPage } = paginationLogic(props)
const { cursor, totalPages, goNext, goPrev, goPage } = paginationLogic(props)
will be interesting For example, which of these is supposed to be ever changing? which isn't once we get to know it, we go to the second step. Find which are ever-changing (reactive) then wrap them into a function in this case, totalPages: props.totalPages becomes totalPages: () => props.totalPages
Nin
Nin•2y ago
I've extracted totalPages from that const and made it a signal in the pagination component now and have changed the return of the helper function to indeed be like what you said. Things are starting to make more sense now goNext goPrev goPage are all functions on their own so they're not changing, I'll extract cursor as well once I've got totalPages working i.e.
const goNext = () => {
const nextCursor = cursor() + 1
setCursor(nextCursor)
}

const goPrev = () => {
const prevCursor = cursor() - 1
setCursor(prevCursor)
return prevCursor
}

const goPage = (e) => {
setCursor(e)
}
const goNext = () => {
const nextCursor = cursor() + 1
setCursor(nextCursor)
}

const goPrev = () => {
const prevCursor = cursor() - 1
setCursor(prevCursor)
return prevCursor
}

const goPage = (e) => {
setCursor(e)
}
Also, total beginner, little background in React, friend of mine pointed me into the direction of Solid and since I want to work with him on hobby projects I stopped my learning development on React and jumped aboard the Solid ship I'll probably go ahead and ask him when he's back cause I can't seem to figure this one out yet I would think though that logically speaking, if I initialize my component with a function as a prop, like I'm doing in the pagination component: totalPages={totalPages()} There would be a signal going to the child component if totalPages is updated, but every console.log in my child component does not run when it gets updated Yeah because if I console log props, it logs the getter function as totalPages however that getter is only executed once and never again 🤔 But when I create a new signal in the pagination component with props.totalPages() I get an error that it's not a function 🤯
lxsmnsyc
lxsmnsyc•2y ago
you can't log in on top-level of the component because as I have mentioned, Solid components only render once
function Pagination(props) {
console.log('This logs once', props.totalPages);

createEffect(() => {
console.log('This logs reactively', props.totalPages);
});
}
function Pagination(props) {
console.log('This logs once', props.totalPages);

createEffect(() => {
console.log('This logs reactively', props.totalPages);
});
}
Nin
Nin•2y ago
So would I need to create a signal in the pagination component that takes props.totalPages and then make a new createEffect that sets totalPages once it gets updated? I think I tried that Actually I think I was looking in the wrong place, it's mainly that the .map isn't executed again Which renders the page numbers in the pagination component
REEEEE
REEEEE•2y ago
try to use the For component
lxsmnsyc
lxsmnsyc•2y ago
props.totalPages is already a signal, based on your code totalPages={totalPages()} is compiled as
{
get totalPages() {
return totalPages();
}
}
{
get totalPages() {
return totalPages();
}
}
hence why we discourage destructuring
Nin
Nin•2y ago
It turned out that because my setTotalPages was wrapped in an if statement it didn't respond properly. I removed my if statement and now it's working
createEffect(() => {
if (!query.loading && !query.error) {
setTotalPages(Math.ceil(query().count / pageSize()))
console.log('Running effect, setting totalPages to:', totalPages())
}
})
createEffect(() => {
if (!query.loading && !query.error) {
setTotalPages(Math.ceil(query().count / pageSize()))
console.log('Running effect, setting totalPages to:', totalPages())
}
})
Removed the if statement in here and voila @lxsmnsyc Sorry for mentioning but wanted to get your opinion on this once more and considering it's old I'm not sure if it'll pass your eyes again. To me this sounds like very strange behaviour and wrapping it in an if statement should be considered good practice(?)
thisbeyond
thisbeyond•2y ago
If an effect doesn't access a reactive signal on evaluation then it won't be tracking it for the next reaction. So in your case, if the if evaluates falsely then you won't track query, pageSize or totalPages for the next iteration. If you want to, then access them outside the if first (or use on helper for explicit tracking).
Nin
Nin•2y ago
Aaaaaaaaaaaa. This makes so much sense now. Of course, the createEffect runs, then it registers how it needs to behave on all subsequent runs. If the first time setTotalPages isn't set because the if is false, it'll never send the signal onwards the moment it does update.
Want results from more Discord servers?
Add your server