How to make react not re render a server side component ?
Answered
Eurasian Blackbird posted this in #help-forum
Eurasian BlackbirdOP
Hello i'm just trying to know how to make a component not being re render (rendered only on first mount but if props change, then not re rendered). Example :
It's not really that complex, but to explain : my search (1) and pagination (2) component are updating my page props (3) so that the "user" list can be updated according to what my user interact with, but the total user count (4) should not be re rendered every time the user interact (make sense : the total count of users doesn't change no matter what). This trigger useless database call. Putting static key is somehow not working.
Thanks for everyone who will try to help me 😄
async function TotalUsersCount() {
const userCount = await fetchUserCount(); // (4)
return <span className="all__title__nb__text">({userCount})</span>;
}
async function TotalUsersCountSkeleton() {
return <span className="all__title__nb__text_skeleton skeleton"></span>;
}
export default async function Page({
searchParams, // (3)
}: {
searchParams?: {
query?: string;
page?: string;
};
}) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const totalUsersFiltered = await fetchTotalUsersFiltered(query);
const totalPages = Math.ceil(totalUsersFiltered / USERS_PER_PAGE);
const usersPromise = fetchFilteredUsers(query, currentPage);
return (
<>
<div className="head__cat">
<h1 className="title__section title__section__text__nb">
<span>Users</span>
<Suspense fallback={<TotalUsersCountSkeleton />} key="static">
<TotalUsersCount key="static" />
</Suspense>
</h1>
<div className="head__right">
<Search placeHolder="Search a user" /> // (1)
</div>
</div>
<Suspense fallback={<UsersSkeleton />} key={query + currentPage}>
<UserList usersPromise={usersPromise} />
</Suspense>
<Pagination totalPages={totalPages} /> // (2)
</>
);
}It's not really that complex, but to explain : my search (1) and pagination (2) component are updating my page props (3) so that the "user" list can be updated according to what my user interact with, but the total user count (4) should not be re rendered every time the user interact (make sense : the total count of users doesn't change no matter what). This trigger useless database call. Putting static key is somehow not working.
Thanks for everyone who will try to help me 😄
9 Replies
@Eurasian Blackbird Hello i'm just trying to know how to make a component not being re render (rendered only on first mount but if props change, then not re rendered). Example :
javascript
async function TotalUsersCount() {
const userCount = await fetchUserCount(); // (4)
return <span className="all__title__nb__text">({userCount})</span>;
}
async function TotalUsersCountSkeleton() {
return <span className="all__title__nb__text_skeleton skeleton"></span>;
}
export default async function Page({
searchParams, // (3)
}: {
searchParams?: {
query?: string;
page?: string;
};
}) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const totalUsersFiltered = await fetchTotalUsersFiltered(query);
const totalPages = Math.ceil(totalUsersFiltered / USERS_PER_PAGE);
const usersPromise = fetchFilteredUsers(query, currentPage);
return (
<>
<div className="head__cat">
<h1 className="title__section title__section__text__nb">
<span>Users</span>
<Suspense fallback={<TotalUsersCountSkeleton />} key="static">
<TotalUsersCount key="static" />
</Suspense>
</h1>
<div className="head__right">
<Search placeHolder="Search a user" /> // (1)
</div>
</div>
<Suspense fallback={<UsersSkeleton />} key={query + currentPage}>
<UserList usersPromise={usersPromise} />
</Suspense>
<Pagination totalPages={totalPages} /> // (2)
</>
);
}
It's not really that complex, but to explain : my search (1) and pagination (2) component are updating my page props (3) so that the "user" list can be updated according to what my user interact with, but the total user count (4) should not be re rendered every time the user interact (make sense : the total count of users doesn't change no matter what). This trigger useless database call. Putting static key is somehow not working.
Thanks for everyone who will try to help me 😄
I think you could try to render <TotalUsersCount /> in a parallel route
// layout.tsx
export default function Layout({
count,
children,
}: {
count: ReactNode;
children: ReactNode;
}) {
return (
<>
<div className="head__cat">
<h1 className="title__section title__section__text__nb">
<span>Users</span>
{count}
</h1>
<div className="head__right">
<Search placeHolder="Search a user" /> // (1)
</div>
</div>
{children}
</>
);
}
// @count/default.tsx
export default function Default() {
return (
<Suspense fallback={<TotalUsersCountSkeleton />} key="static">
<TotalUsersCount key="static" />
</Suspense>
)
}
async function TotalUsersCount() {
const userCount = await fetchUserCount(); // (4)
return <span className="all__title__nb__text">({userCount})</span>;
}
// pages
export default function Page({
searchParams, // (3)
}: {
searchParams?: {
query?: string;
page?: string;
};
}) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const totalUsersFiltered = await fetchTotalUsersFiltered(query);
const totalPages = Math.ceil(totalUsersFiltered / USERS_PER_PAGE);
const usersPromise = fetchFilteredUsers(query, currentPage);
return (
<Suspense fallback={<UsersSkeleton />} key={query + currentPage}>
<UserList usersPromise={usersPromise} />
</Suspense>
<Pagination totalPages={totalPages} />
)
}@Ray I think you could try to render <TotalUsersCount /> in a parallel route
ts
// layout.tsx
export default function Layout({
count,
children,
}: {
count: ReactNode;
children: ReactNode;
}) {
return (
<>
<div className="head__cat">
<h1 className="title__section title__section__text__nb">
<span>Users</span>
{count}
</h1>
<div className="head__right">
<Search placeHolder="Search a user" /> // (1)
</div>
</div>
{children}
</>
);
}
// @count/default.tsx
export default function Default() {
return (
<Suspense fallback={<TotalUsersCountSkeleton />} key="static">
<TotalUsersCount key="static" />
</Suspense>
)
}
async function TotalUsersCount() {
const userCount = await fetchUserCount(); // (4)
return <span className="all__title__nb__text">({userCount})</span>;
}
// pages
export default function Page({
searchParams, // (3)
}: {
searchParams?: {
query?: string;
page?: string;
};
}) {
const query = searchParams?.query || '';
const currentPage = Number(searchParams?.page) || 1;
const totalUsersFiltered = await fetchTotalUsersFiltered(query);
const totalPages = Math.ceil(totalUsersFiltered / USERS_PER_PAGE);
const usersPromise = fetchFilteredUsers(query, currentPage);
return (
<Suspense fallback={<UsersSkeleton />} key={query + currentPage}>
<UserList usersPromise={usersPromise} />
</Suspense>
<Pagination totalPages={totalPages} />
)
}
Eurasian BlackbirdOP
Using layout is a good idea, I think it might solve my problem, however, I don't understand why I should use a parralel routes ? I mean, the layout doesn't re render so just putting my "count" logic in the layout should do the job no ?
@Eurasian Blackbird Using layout is a good idea, I think it might solve my problem, however, I don't understand why I should use a parralel routes ? I mean, the layout doesn't re render so just putting my "count" logic in the layout should do the job no ?
yeah render it on layout.tsx should do that too
Answer
Eurasian BlackbirdOP
okay, i'm gonna try that thank you. I'll tell u if that works
Eurasian BlackbirdOP
just realised I have others pages nested inside. I cna't do that cause the count information should not be displayed on those nested pages
@Eurasian Blackbird just realised I have others pages nested inside. I cna't do that cause the count information should not be displayed on those nested pages
you could create a route-group for the page which need to show the count
Eurasian BlackbirdOP
yes true
coming back
works perfectly ! Thank you very much @Ray