@@ -412,127 +412,6 @@ export default function App({ viewName, query }) {
412412}
413413` ` `
414414
415- ## Pagination and Sorting
416-
417- React views receive a ` stateHash` prop — a short identifier for this view's state context. Use it to set pagination and sort parameters via ` set_state_field` , which updates the URL and triggers a re-render with the new page.
418-
419- The view also receives ` totalCount` when a page size is active, so you can show "page X of Y".
420-
421- **Available state keys** (replace ` ${stateHash}` with the actual value):
422-
423- | Key | Effect |
424- | ------------------------ | ---------------------------------- |
425- | ` _${stateHash}_page` | Current page number (1-based) |
426- | ` _${stateHash}_pagesize` | Rows per page |
427- | ` _${stateHash}_sortby` | Field name to sort by |
428- | ` _${stateHash}_sortdesc` | Set to ` " on" ` for descending order |
429-
430- **Copy-paste example** — paste this into a table-based React view:
431-
432- ` ` ` javascript
433- import React , { useEffect } from " react" ;
434-
435- const PAGE_SIZE = 5 ;
436-
437- export default function App ({ rows, state, stateHash, totalCount }) {
438- useEffect (() => {
439- if (! state[` _${ stateHash} _pagesize` ]) {
440- set_state_field (` _${ stateHash} _pagesize` , PAGE_SIZE );
441- }
442- }, []);
443-
444- const currentPage = state[` _${ stateHash} _page` ]
445- ? parseInt (state[` _${ stateHash} _page` ])
446- : 1 ;
447- const sortBy = state[` _${ stateHash} _sortby` ] || " " ;
448- const sortDesc = !! state[` _${ stateHash} _sortdesc` ];
449- const totalPages = totalCount ? Math .ceil (totalCount / PAGE_SIZE ) : null ;
450-
451- const setPage = (n ) => set_state_field (` _${ stateHash} _page` , n);
452- const setPageSize = (n ) =>
453- set_state_fields ({
454- [` _${ stateHash} _pagesize` ]: n,
455- [` _${ stateHash} _page` ]: 1 ,
456- });
457- const setSort = (field ) => {
458- const newSortDesc = sortBy === field ? (sortDesc ? " " : " on" ) : " " ;
459- const kvs = {
460- [` _${ stateHash} _sortby` ]: field,
461- [` _${ stateHash} _sortdesc` ]: newSortDesc,
462- };
463- const currentPageSize = state[` _${ stateHash} _pagesize` ];
464- if (currentPageSize) kvs[` _${ stateHash} _pagesize` ] = currentPageSize;
465- set_state_fields (kvs);
466- };
467-
468- if (! rows || rows .length === 0 ) return < p> No rows found.< / p> ;
469- const columns = Object .keys (rows[0 ]);
470-
471- return (
472- < div>
473- < table className= " table table-striped" >
474- < thead>
475- < tr>
476- {columns .map ((col ) => (
477- < th
478- key= {col}
479- onClick= {() => setSort (col)}
480- style= {{ cursor: " pointer" }}
481- >
482- {col}
483- {sortBy === col ? (sortDesc ? " ▼" : " ▲" ) : " " }
484- < / th>
485- ))}
486- < / tr>
487- < / thead>
488- < tbody>
489- {rows .map ((row , i ) => (
490- < tr key= {i}>
491- {columns .map ((col ) => (
492- < td key= {col}> {String (row[col] ?? " " )}< / td>
493- ))}
494- < / tr>
495- ))}
496- < / tbody>
497- < / table>
498-
499- < div className= " d-flex align-items-center gap-3 mt-2" >
500- < button
501- className= " btn btn-sm btn-outline-secondary"
502- disabled= {currentPage <= 1 }
503- onClick= {() => setPage (currentPage - 1 )}
504- >
505- ‹ Prev
506- < / button>
507- < span>
508- Page {currentPage}
509- {totalPages ? ` of ${ totalPages} ` : " " }
510- < / span>
511- < button
512- className= " btn btn-sm btn-outline-secondary"
513- disabled= {
514- totalPages ? currentPage >= totalPages : rows .length < PAGE_SIZE
515- }
516- onClick= {() => setPage (currentPage + 1 )}
517- >
518- Next ›
519- < / button>
520- < select
521- className= " form-select form-select-sm w-auto"
522- value= {state[` _${ stateHash} _pagesize` ] || PAGE_SIZE }
523- onChange= {(e ) => setPageSize (Number (e .target .value ))}
524- >
525- {[5 , 10 , 25 , 50 ].map ((n ) => (
526- < option key= {n} value= {n}>
527- {n} per page
528- < / option>
529- ))}
530- < / select>
531- < / div>
532- < / div>
533- );
534- }
535- ` ` `
536415
537416## Components
538417
0 commit comments