David Alonso
David Alonso8mo ago

Unknown cause of janky behavior in React Component

I'm building the following component which uses the standard pattern of binding convex data to a UI component directly. However, as you can see in the video, when I update data in the Convex dashboard there's some strange behavior where the state initially updates as desired, but then the component completely rebuilds, which is undesired. Am I doing something wrong?
const SortPage: React.FC<SortPageProps> = ({ navigateTo, activeTableView }) => {
const cSorts = useQuery(api.queries.tableViews.getSortsByTableViewId, {
tableViewId: activeTableView._id,
});

const cUpdateSorts = useMutation(api.mutations.tableViews.updateSorts);
return (
<>
<div className="px-4 flex flex-col gap-4 mb-4">
<div className="flex flex-col gap-2">
{cSorts?.length === 0 && newSorts.length === 0 ? (
<div className="px-4 pt-2 pb-4 flex flex-col items-center justify-center text-center">
<PiArrowUpDuoStroke className="h-12 w-12 text-primary/30 mb-4" />
<p className="text-sm text-primary/60 font-medium mb-2">
No sorting added yet
</p>
<p className="text-xs text-primary/40">
Add a sort to sort your results
</p>
</div>
) : (
<>
<p className="text-sm font-medium text-primary/60">Sort by</p>
<div className="flex flex-col gap-3">
{cSorts?.map((sort, index) => {
return (
<SortItem
key={index}
type="existing"
sort={sort}
collectionId={activeTableView.collectionId}

/>
);
})}

</div>
</>
)}
</div>
</div>
...
const SortPage: React.FC<SortPageProps> = ({ navigateTo, activeTableView }) => {
const cSorts = useQuery(api.queries.tableViews.getSortsByTableViewId, {
tableViewId: activeTableView._id,
});

const cUpdateSorts = useMutation(api.mutations.tableViews.updateSorts);
return (
<>
<div className="px-4 flex flex-col gap-4 mb-4">
<div className="flex flex-col gap-2">
{cSorts?.length === 0 && newSorts.length === 0 ? (
<div className="px-4 pt-2 pb-4 flex flex-col items-center justify-center text-center">
<PiArrowUpDuoStroke className="h-12 w-12 text-primary/30 mb-4" />
<p className="text-sm text-primary/60 font-medium mb-2">
No sorting added yet
</p>
<p className="text-xs text-primary/40">
Add a sort to sort your results
</p>
</div>
) : (
<>
<p className="text-sm font-medium text-primary/60">Sort by</p>
<div className="flex flex-col gap-3">
{cSorts?.map((sort, index) => {
return (
<SortItem
key={index}
type="existing"
sort={sort}
collectionId={activeTableView.collectionId}

/>
);
})}

</div>
</>
)}
</div>
</div>
...
4 Replies
Michal Srb
Michal Srb8mo ago
Probably not related to Convex, something is causing the component to unmount. Try to simplify the problem by removing code to see what's causing what. Maybe you have another useQuery in a parent component that also reacts to the change in data.
David Alonso
David AlonsoOP8mo ago
Okay I was able to resolve the issue by updating the query of the parent to not fetch the entire document (the one I was updating in the video) and instead subscribe to the specific field that was needed on the parent. However, this feels like it increases the number of subscriptions and the problem would persist if the parent needs the same data as the child. In the latter case, would you query for the shared data in the parent and pass it down to the child? or if both a parent and child need access to a "tableView" document would you have the parent do a getTableViewById query, pass the id to the child and have the child run the same query?
Michal Srb
Michal Srb8mo ago
I think the issue is not in the queries, but in the fact that rerendering the parent messes up your UI. Maybe this is because of key on the child component?
David Alonso
David AlonsoOP8mo ago
hmm I didn't have to change the key of SortItem to get it to work, but I updated the interface of the component to be
const SortPage: React.FC<SortPageProps> = ({ navigateTo, activeTableViewId }) => {
const SortPage: React.FC<SortPageProps> = ({ navigateTo, activeTableViewId }) => {
And narrowed down the scope of the tableViewQuery in the parent component Okay it seems like passing around Ids + using React.memo to wrap components works well

Did you find this page helpful?