Fully controlled component props and callbacks + docs

This commit is contained in:
Tanner Linsley
2017-01-12 11:06:09 -07:00
parent 4b2fa4e47d
commit 75c31b9354
4 changed files with 121 additions and 60 deletions
+33 -2
View File
@@ -30,6 +30,7 @@
- [Header Groups](#header-groups)
- [Sub Tables & Components](#sub-tables-components)
- [Server-side Data](#server-side-data)
- [Fully Controlled Component](#fully-controlled-component)
- [Multi-sort](#multi-sort)
- [Component Overrides](#component-overrides)
@@ -123,11 +124,15 @@ These are all of the available props (and their default values) for the main `<R
tdStyle: {}, // style object for the `td` component
paginationStyle: {}, // style object for the `paginination` component
// Controlled State (see Using as a Fully Controlled Component below)
// Controlled Props (see Using as a Fully Controlled Component below)
page: undefined,
pageSize: undefined,
sorting: undefined,
visibleSubComponents: undefined
visibleSubComponents: undefined,
// Controlled Callbacks
onExpand: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
}
```
@@ -266,6 +271,32 @@ If you want to handle pagination, and sorting on the server, `react-table` makes
For a detailed example, take a peek at our [async table mockup](https://github.com/tannerlinsley/react-table/blob/master/example/src/screens/async.js)
## Fully Controlled Component
React Table by default works fantastically out of the box, but you can achieve even more control and customization if you choose to maintain the state yourself. It is very easy to do, even if you only want to manage *parts* of the state.
Here are the props and their corresponding callbacks that control the state of the a table:
```javascript
<ReactTable
// Props
page={0} // the index of the page you wish to display
pageSize={20} // the number of rows per page to be displayed
sorting={[{
id: 'lastName',
asc: true
}, {
id: 'firstName',
asc: true
}]} // the sorting model for the table
visibleSubComponents={[1,4,5]} // The row indexes on the current page that should appear expanded
// Callbacks
onPageChange={(pageIndex) => {...}} // Called when the page index is changed by the user
onPageSizeChange={(pageSize, pageIndex) => {...}} // Called when the pageSize is changed by the user. The resolve page is also sent to maintain approximate position in the data
onSortingChange={(column, shiftKey) => {...}} // Called when a sortable column header is clicked with the column itself and if the shiftkey was held.
onExpand={(index, event) => {...}} // Called when an expander is clicked. Use this to manage `visibleSubComponents`
/>
```
## Multi-Sort
When clicking on a column header, hold shift to multi-sort! You can toggle `ascending` `descending` and `none` for multi-sort columns. Clicking on a header without holding shift will clear the multi-sort and replace it with the single sort of that column. It's quite handy!
+53 -44
View File
@@ -17,13 +17,18 @@ export const ReactTableDefaults = {
showPageJump: true,
expanderColumnWidth: 30,
// State Overrides (for controlled-component style)
// Controlled State Overrides
// page
// pageSize
// sorting
// visibleSubComponents
// Callbacks
// Controlled State Callbacks
onExpand: undefined,
onPageChange: undefined,
onPageSizeChange: undefined,
// General Callbacks
onChange: () => null,
onTrClick: () => null,
// Classes
@@ -86,17 +91,17 @@ export const ReactTableDefaults = {
)
},
TdComponent: _.makeTemplateComponent('rt-td'),
ExpanderComponent: ({isOpen, toggle, ...rest}) => {
ExpanderComponent: ({isExpanded, toggle, ...rest}) => {
return (
<div
className={classnames('rt-expander', isOpen && '-open')}
className={classnames('rt-expander', isExpanded && '-open')}
{...rest}
/>
)
},
PaginationComponent: Pagination,
PreviousComponent: null,
NextComponent: null,
PreviousComponent: undefined,
NextComponent: undefined,
LoadingComponent: ({loading, loadingText}) => (
<div className={classnames('-loading', {'-active': loading})}>
<div className='-loading-inner'>
@@ -116,7 +121,7 @@ export default React.createClass({
page: 0,
pageSize: this.props.defaultPageSize || 10,
sorting: false,
visibleSubComponents: {}
visibleSubComponents: []
}
},
@@ -125,6 +130,7 @@ export default React.createClass({
},
render () {
const resolvedProps = this.getResolvedState()
const {
className,
style,
@@ -146,18 +152,11 @@ export default React.createClass({
trStyleCallback,
tdStyle,
showPagination,
showPageSizeOptions,
pageSizeOptions,
showPageJump,
previousText,
nextText,
pageText,
ofText,
rowsText,
paginationClassName,
expanderColumnWidth,
manual,
loadingText,
onExpand,
// State
visibleSubComponents,
loading,
@@ -173,11 +172,9 @@ export default React.createClass({
TdComponent,
ExpanderComponent,
PaginationComponent,
PreviousComponent,
NextComponent,
LoadingComponent,
SubComponent
} = this.getResolvedState()
} = resolvedProps
// Build Columns
const decoratedColumns = []
@@ -373,6 +370,8 @@ export default React.createClass({
index: row.__index,
viewIndex: i
}
const visibleSubComponentIndex = visibleSubComponents.indexOf(i)
const isExpanded = visibleSubComponentIndex > -1
return (
<TrGroupComponent key={i}>
<TrComponent
@@ -387,17 +386,28 @@ export default React.createClass({
flex: `0 0 auto`,
width: `${expanderColumnWidth}px`
})}
onClick={() => {
onClick={(e) => {
if (onExpand) {
return onExpand(i, e)
}
if (isExpanded) {
return this.setState({
visibleSubComponents: [
...visibleSubComponents.slice(0, visibleSubComponentIndex - 1),
...visibleSubComponents.slice(visibleSubComponentIndex + 1)
]
})
}
this.setState({
visibleSubComponents: {
...visibleSubComponents,
[i]: !visibleSubComponents[i]
}
visibleSubComponents: [
...visibleSubComponents,
i
]
})
}}
>
<ExpanderComponent
isOpen={visibleSubComponents[i]}
isExpanded={isExpanded}
/>
</ThComponent>
)}
@@ -424,7 +434,7 @@ export default React.createClass({
)
})}
</TrComponent>
{SubComponent && visibleSubComponents[i] ? (
{SubComponent && isExpanded ? (
SubComponent(rowInfo)
) : null}
</TrGroupComponent>
@@ -468,25 +478,12 @@ export default React.createClass({
</TableComponent>
{showPagination && (
<PaginationComponent
page={page}
{...resolvedProps}
pagesLength={pagesLength}
pageSize={pageSize}
showPageSizeOptions={showPageSizeOptions}
pageSizeOptions={pageSizeOptions}
showPageJump={showPageJump}
canPrevious={canPrevious}
canNext={canNext}
previousText={previousText}
nextText={nextText}
pageText={pageText}
ofText={ofText}
rowsText={rowsText}
previousComponent={PreviousComponent}
nextComponent={NextComponent}
//
onChange={this.setPage}
onPageSizeChange={this.setPageSize}
//
onPageChange={this.onPageChange}
onPageSizeChange={this.onPageSizeChange}
className={paginationClassName}
/>
)}
@@ -577,18 +574,30 @@ export default React.createClass({
},
// User actions
setPage (page) {
onPageChange (page) {
const { onPageChange } = this.props
if (onPageChange) {
return onPageChange(page)
}
this.setState({
visibleSubComponents: {},
visibleSubComponents: [],
page
}, () => {
this.fireOnChange()
})
},
setPageSize (newPageSize) {
onPageSizeChange (newPageSize) {
const { onPageSizeChange } = this.props
const { pageSize, page } = this.getResolvedState()
// Normalize the page to display
const currentRow = pageSize * page
const newPage = Math.floor(currentRow / pageSize)
if (onPageSizeChange) {
return onPageSizeChange(newPageSize, newPage)
}
this.setState({
pageSize: newPageSize,
page: newPage
+7 -6
View File
@@ -22,7 +22,7 @@ export default React.createClass({
changePage (page) {
page = this.getSafePage(page)
this.setState({page})
this.props.onChange(page)
this.props.onPageChange(page)
},
applyPage (e) {
e && e.preventDefault()
@@ -31,8 +31,10 @@ export default React.createClass({
},
render () {
const {
page,
// Computed
pagesLength,
// Props
page,
showPageSizeOptions,
pageSizeOptions,
pageSize,
@@ -40,12 +42,11 @@ export default React.createClass({
canPrevious,
canNext,
onPageSizeChange,
className
className,
PreviousComponent = defaultButton,
NextComponent = defaultButton
} = this.props
const PreviousComponent = this.props.previousComponent || defaultButton
const NextComponent = this.props.nextComponent || defaultButton
return (
<div
className={classnames(className, '-pagination')}
+28 -8
View File
@@ -39,19 +39,21 @@ export default () => {
data={data}
columns={columns}
defaultPageSize={10}
subComponent={(row) => {
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!. It has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={10}
subComponent={(row) => {
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table! It even has access to the row data: </em>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
@@ -96,9 +98,27 @@ export default (
data={data}
columns={columns}
defaultPageSize={10}
subComponent={(row) => {
SubComponent={(row) => {
return (
<code><pre>{JSON.stringify(row, null, 2)}</pre></code>
<div style={{padding: '20px'}}>
<em>You can put any component you want here, even another React Table!</em>
<br />
<br />
<ReactTable
data={data}
columns={columns}
defaultPageSize={3}
showPagination={false}
SubComponent={(row) => {
return (
<div style={{padding: '20px'}}>
<em>It even has access to the row data: </em>
<CodeHighlight>{() => JSON.stringify(row, null, 2)}</CodeHighlight>
</div>
)
}}
/>
</div>
)
}}
/>