Skip to content

useRow causes infinite re-render loop when row contains object or array cells #287

@deankerr

Description

@deankerr

Describe the bug

useRow triggers an infinite re-render loop when any cell in the row uses the new object or array cell type (v8).

The root cause is in objIsEqual (src/common/obj.ts:76), which is used by useListenable to determine if the row has changed. Its default leaf comparator uses === (strict reference equality). Since getRow calls mapToObj(..., decodeIfJson) which runs JSON.parse() on every object/array cell — producing new references each time — the equality check always fails for rows containing these cell types.

Specifically:

  • Array cells fail because isObject(array) returns false, so they fall through to === which fails on different references.
  • Object cells containing arrays fail for the same reason at the nested level.
  • Pure plain-object cells (no nested arrays) work because objIsEqual recurses into them.

Steps to Reproduce the Bug or Issue

  1. Create a store with an object or array cell schema
  2. Set a row with an object/array cell value
  3. Use useRow in a React component to read that row
  4. Component enters an infinite re-render loop
const store = createStore()
  .setTablesSchema({ t1: { c1: { type: 'object' } } })
  .setRow('t1', 'r1', { c1: { key: 'value' } });

const Test = () => {
  const row = useRow('t1', 'r1', store);
  return <div>{JSON.stringify(row)}</div>;
};
// Infinite re-render loop

Expected behavior

useRow should return a stable reference when the row data hasn't changed, consistent with how useCell behaves for object/array cell types.

Platform

  • TinyBase v8.0.1
  • React 18/19

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions