@@ -6,6 +6,7 @@ export interface CoreRow<TData extends RowData> {
66 _getAllCellsByColumnId : ( ) => Record < string , Cell < TData , unknown > >
77 _uniqueValuesCache : Record < string , unknown >
88 _valuesCache : Record < string , unknown >
9+ clone : ( ) => Row < TData >
910 /**
1011 * The depth of the row (if nested or grouped) relative to the root row array.
1112 * @link [API Docs](https://tanstack.com/table/v8/docs/api/core/row#depth)
@@ -92,26 +93,29 @@ export interface CoreRow<TData extends RowData> {
9293 subRows : Row < TData > [ ]
9394}
9495
95- export const createRow = < TData extends RowData > (
96- table : Table < TData > ,
97- id : string ,
98- original : TData ,
99- rowIndex : number ,
100- depth : number ,
101- subRows ?: Row < TData > [ ] ,
102- parentId ?: string
103- ) : Row < TData > => {
104- let row : CoreRow < TData > = {
105- id,
106- index : rowIndex ,
107- original,
108- depth,
109- parentId,
110- _valuesCache : { } ,
111- _uniqueValuesCache : { } ,
112- getValue : columnId => {
113- if ( row . _valuesCache . hasOwnProperty ( columnId ) ) {
114- return row . _valuesCache [ columnId ]
96+ const rowProtosByTable = new WeakMap < Table < any > , any > ( )
97+
98+ /**
99+ * Creates a table-specific row prototype object to hold shared row methods, including from all the
100+ * features that have been registered on the table.
101+ */
102+ export function getRowProto < TData extends RowData > ( table : Table < TData > ) {
103+ let rowProto = rowProtosByTable . get ( table )
104+
105+ if ( ! rowProto ) {
106+ const proto = { } as CoreRow < TData >
107+
108+ proto . clone = function ( ) {
109+ return Object . assign ( Object . create ( Object . getPrototypeOf ( this ) ) , this )
110+ }
111+
112+ // Make the default fallback value available on the proto itself to avoid duplicating it on every row instance
113+ // even if it's not used. This is safe as long as we don't mutate the value directly.
114+ proto . subRows = [ ] as const
115+
116+ proto . getValue = function ( columnId : string ) {
117+ if ( this . _valuesCache . hasOwnProperty ( columnId ) ) {
118+ return this . _valuesCache [ columnId ]
115119 }
116120
117121 const column = table . getColumn ( columnId )
@@ -120,16 +124,22 @@ export const createRow = <TData extends RowData>(
120124 return undefined
121125 }
122126
123- row . _valuesCache [ columnId ] = column . accessorFn (
124- row . original as TData ,
125- rowIndex
127+ this . _valuesCache [ columnId ] = column . accessorFn (
128+ this . original as TData ,
129+ this . index
126130 )
127131
128- return row . _valuesCache [ columnId ] as any
129- } ,
130- getUniqueValues : columnId => {
131- if ( row . _uniqueValuesCache . hasOwnProperty ( columnId ) ) {
132- return row . _uniqueValuesCache [ columnId ]
132+ return this . _valuesCache [ columnId ] as any
133+ }
134+
135+ proto . getUniqueValues = function ( columnId : string ) {
136+ if ( ! this . hasOwnProperty ( '_uniqueValuesCache' ) ) {
137+ // lazy-init cache on the instance
138+ this . _uniqueValuesCache = { }
139+ }
140+
141+ if ( this . _uniqueValuesCache . hasOwnProperty ( columnId ) ) {
142+ return this . _uniqueValuesCache [ columnId ]
133143 }
134144
135145 const column = table . getColumn ( columnId )
@@ -139,46 +149,58 @@ export const createRow = <TData extends RowData>(
139149 }
140150
141151 if ( ! column . columnDef . getUniqueValues ) {
142- row . _uniqueValuesCache [ columnId ] = [ row . getValue ( columnId ) ]
143- return row . _uniqueValuesCache [ columnId ]
152+ this . _uniqueValuesCache [ columnId ] = [ this . getValue ( columnId ) ]
153+ return this . _uniqueValuesCache [ columnId ]
144154 }
145155
146- row . _uniqueValuesCache [ columnId ] = column . columnDef . getUniqueValues (
147- row . original as TData ,
148- rowIndex
156+ this . _uniqueValuesCache [ columnId ] = column . columnDef . getUniqueValues (
157+ this . original as TData ,
158+ this . index
149159 )
150160
151- return row . _uniqueValuesCache [ columnId ] as any
152- } ,
153- renderValue : columnId =>
154- row . getValue ( columnId ) ?? table . options . renderFallbackValue ,
155- subRows : subRows ?? [ ] ,
156- getLeafRows : ( ) => flattenBy ( row . subRows , d => d . subRows ) ,
157- getParentRow : ( ) =>
158- row . parentId ? table . getRow ( row . parentId , true ) : undefined ,
159- getParentRows : ( ) => {
161+ return this . _uniqueValuesCache [ columnId ] as any
162+ }
163+
164+ proto . renderValue = function ( columnId : string ) {
165+ return this . getValue ( columnId ) ?? table . options . renderFallbackValue
166+ }
167+
168+ proto . getLeafRows = function ( ) {
169+ return flattenBy ( this . subRows , d => d . subRows )
170+ }
171+
172+ proto . getParentRow = function ( ) {
173+ return this . parentId ? table . getRow ( this . parentId , true ) : undefined
174+ }
175+
176+ proto . getParentRows = function ( ) {
160177 let parentRows : Row < TData > [ ] = [ ]
161- let currentRow = row
178+ let currentRow = this
162179 while ( true ) {
163180 const parentRow = currentRow . getParentRow ( )
164181 if ( ! parentRow ) break
165182 parentRows . push ( parentRow )
166183 currentRow = parentRow
167184 }
168185 return parentRows . reverse ( )
169- } ,
170- getAllCells : memo (
171- ( ) => [ table . getAllLeafColumns ( ) ] ,
172- leafColumns => {
186+ }
187+
188+ proto . getAllCells = memo (
189+ function ( this : Row < TData > ) {
190+ return [ this , table . getAllLeafColumns ( ) ]
191+ } ,
192+ ( row , leafColumns ) => {
173193 return leafColumns . map ( column => {
174- return createCell ( table , row as Row < TData > , column , column . id )
194+ return createCell ( table , row , column , column . id )
175195 } )
176196 } ,
177197 getMemoOptions ( table . options , 'debugRows' , 'getAllCells' )
178- ) ,
198+ )
179199
180- _getAllCellsByColumnId : memo (
181- ( ) => [ row . getAllCells ( ) ] ,
200+ proto . _getAllCellsByColumnId = memo (
201+ function ( this : Row < TData > ) {
202+ return [ this . getAllCells ( ) ]
203+ } ,
182204 allCells => {
183205 return allCells . reduce (
184206 ( acc , cell ) => {
@@ -189,7 +211,36 @@ export const createRow = <TData extends RowData>(
189211 )
190212 } ,
191213 getMemoOptions ( table . options , 'debugRows' , 'getAllCellsByColumnId' )
192- ) ,
214+ )
215+
216+ rowProtosByTable . set ( table , proto )
217+ rowProto = proto
218+ }
219+
220+ return rowProto as CoreRow < TData >
221+ }
222+
223+ export const createRow = < TData extends RowData > (
224+ table : Table < TData > ,
225+ id : string ,
226+ original : TData ,
227+ rowIndex : number ,
228+ depth : number ,
229+ subRows ?: Row < TData > [ ] ,
230+ parentId ?: string
231+ ) : Row < TData > => {
232+ const row : CoreRow < TData > = Object . create ( getRowProto ( table ) )
233+ Object . assign ( row , {
234+ id,
235+ index : rowIndex ,
236+ original,
237+ depth,
238+ parentId,
239+ _valuesCache : { } ,
240+ } )
241+
242+ if ( subRows ) {
243+ row . subRows = subRows
193244 }
194245
195246 for ( let i = 0 ; i < table . _features . length ; i ++ ) {
0 commit comments