Skip to content

Commit 6a26946

Browse files
committed
fix(Changing data in rows passed into useTable does not update rows): (#16)
Fix bug causing updated data not updating rows due to improper memoization
1 parent b448904 commit 6a26946

5 files changed

Lines changed: 49 additions & 25 deletions

File tree

src/hooks.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ const createReducer = <T extends DataType>() => (
2020
action: TableAction<T>
2121
): TableState<T> => {
2222
switch (action.type) {
23+
case 'SET_ROWS':
24+
return {
25+
...state,
26+
rows: action.data,
27+
originalRows: action.data,
28+
};
2329
case 'TOGGLE_SORT':
2430
if (!(action.columnName in state.columnsByName)) {
2531
throw new Error(`Invalid column, ${action.columnName} not found`);
@@ -216,6 +222,7 @@ export const useTable = <T extends DataType>(
216222
}, [data, columnsWithSorting, columnsByName]);
217223

218224
const reducer = createReducer<T>();
225+
219226
const [state, dispatch] = useReducer(reducer, {
220227
columns: columnsWithSorting,
221228
columnsByName: columnsByName,
@@ -226,6 +233,12 @@ export const useTable = <T extends DataType>(
226233
filterOn: false,
227234
});
228235

236+
useEffect(() => {
237+
if (tableData.length > 0) {
238+
dispatch({ type: 'SET_ROWS', data: tableData });
239+
}
240+
}, [tableData]);
241+
229242
const headers: HeaderType<T>[] = useMemo(() => {
230243
return [
231244
...state.columns.map(column => {

src/test/filtering.spec.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ test('Should filter by text', () => {
9898
</thead>
9999
<tbody>
100100
{rows.map((row, idx) => (
101-
<tr data-testid={`row-${idx}`} aria-label="row" key={idx}>
101+
<tr data-testid={`row-${idx}`} role="table-row" key={idx}>
102102
{row.cells.map((cell, idx) => (
103103
<td key={idx}>{cell.render()}</td>
104104
))}
@@ -114,20 +114,20 @@ test('Should filter by text', () => {
114114

115115
const input = table.getByTestId('input');
116116

117-
expect(table.getAllByLabelText('row')).toHaveLength(3);
117+
expect(table.getAllByRole('table-row')).toHaveLength(3);
118118

119119
fireEvent.change(input, { target: { value: 'Frodo' } });
120120

121-
expect(table.getAllByLabelText('row')).toHaveLength(1);
121+
expect(table.getAllByRole('table-row')).toHaveLength(1);
122122
let firstRow = table.getByTestId('row-0');
123123

124124
let { getByText } = within(firstRow);
125125
expect(getByText('Frodo')).toBeInTheDocument();
126126

127127
fireEvent.change(input, { target: { value: '' } });
128128
expect(table.getByText('Bilbo')).toBeInTheDocument();
129-
expect(table.getAllByLabelText('row')).toHaveLength(3);
129+
expect(table.getAllByRole('table-row')).toHaveLength(3);
130130

131131
fireEvent.change(input, { target: { value: 'Bag' } });
132-
expect(table.getAllByLabelText('row')).toHaveLength(2);
132+
expect(table.getAllByRole('table-row')).toHaveLength(2);
133133
});

src/test/sorting.spec.tsx

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Table = <T extends {}>({
4141
</thead>
4242
<tbody>
4343
{rows.map((row, idx) => (
44-
<tr data-testid={`row-${idx}`} aria-label="row" key={idx}>
44+
<tr data-testid={`row-${idx}`} role="table-row" key={idx}>
4545
{row.cells.map((cell, idx) => (
4646
<td key={idx}>{cell.render()}</td>
4747
))}
@@ -58,7 +58,7 @@ test('Should render a table with sorting enabled', () => {
5858

5959
const firstNameColumn = screen.getByTestId('column-firstName');
6060

61-
expect(screen.queryAllByLabelText('row')).toHaveLength(10);
61+
expect(screen.queryAllByRole('table-row')).toHaveLength(10);
6262

6363
// should be sorted in ascending order
6464
fireEvent.click(firstNameColumn);
@@ -95,17 +95,17 @@ test('Should sort by dates correctly', () => {
9595
);
9696
},
9797
};
98-
const rtl = render(<Table columns={columns} data={data} />);
98+
render(<Table columns={columns} data={data} />);
9999

100-
const dateColumn = rtl.getByTestId('column-birthDate');
100+
const dateColumn = screen.getByTestId('column-birthDate');
101101

102102
// should be sorted in ascending order
103103
fireEvent.click(dateColumn);
104104

105-
expect(rtl.queryByTestId('sorted-birthDate')).toBeInTheDocument();
105+
expect(screen.queryByTestId('sorted-birthDate')).toBeInTheDocument();
106106

107-
let firstRow = rtl.getByTestId('row-0');
108-
let lastRow = rtl.getByTestId('row-2');
107+
let firstRow = screen.getByTestId('row-0');
108+
let lastRow = screen.getByTestId('row-2');
109109

110110
let { getByText } = within(firstRow);
111111
expect(getByText('Bilbo')).toBeInTheDocument();
@@ -115,8 +115,8 @@ test('Should sort by dates correctly', () => {
115115
// should be sorted in descending order
116116
fireEvent.click(dateColumn);
117117

118-
firstRow = rtl.getByTestId('row-0');
119-
lastRow = rtl.getByTestId('row-2');
118+
firstRow = screen.getByTestId('row-0');
119+
lastRow = screen.getByTestId('row-2');
120120

121121
({ getByText } = within(firstRow));
122122
expect(getByText('Frodo')).toBeInTheDocument();

src/test/table.spec.tsx

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react';
2-
import { render } from '@testing-library/react';
2+
import { render, screen } from '@testing-library/react';
33
import '@testing-library/jest-dom/extend-expect';
44
import { renderHook } from '@testing-library/react-hooks';
55

@@ -51,7 +51,7 @@ const Table = ({
5151
</thead>
5252
<tbody>
5353
{rows.map((row, idx) => (
54-
<tr key={idx}>
54+
<tr role="table-row" key={idx}>
5555
{row.cells.map((cell, idx) => (
5656
<td key={idx}>{cell.render()}</td>
5757
))}
@@ -63,12 +63,12 @@ const Table = ({
6363
};
6464

6565
test('Should render a basic table', () => {
66-
const rtl = render(<Table columns={columns} data={data} />);
66+
render(<Table columns={columns} data={data} />);
6767

68-
expect(rtl.getByText('Frodo')).toBeInTheDocument();
69-
expect(rtl.getByText('Baggins')).toBeInTheDocument();
70-
expect(rtl.getByText('Samwise')).toBeInTheDocument();
71-
expect(rtl.getByText('Gamgee')).toBeInTheDocument();
68+
expect(screen.getByText('Frodo')).toBeInTheDocument();
69+
expect(screen.getByText('Baggins')).toBeInTheDocument();
70+
expect(screen.getByText('Samwise')).toBeInTheDocument();
71+
expect(screen.getByText('Gamgee')).toBeInTheDocument();
7272
});
7373

7474
const reverseData = [
@@ -89,6 +89,16 @@ test('Should be equal regardless of field order in data', () => {
8989
expect(normalTl.asFragment()).toEqual(reverseTl.asFragment());
9090
});
9191

92+
test('Should update table rows when data changes', () => {
93+
const { rerender } = render(<Table columns={columns} data={data} />);
94+
expect(screen.getAllByRole('table-row')).toHaveLength(2);
95+
96+
let newData = [...data, { firstName: 'Bilbo', lastName: 'Baggins' }];
97+
rerender(<Table columns={columns} data={newData} />);
98+
99+
expect(screen.getAllByRole('table-row')).toHaveLength(3);
100+
});
101+
92102
const columnsWithRender: ColumnType<any>[] = [
93103
{
94104
name: 'firstName',
@@ -102,9 +112,9 @@ const columnsWithRender: ColumnType<any>[] = [
102112
];
103113

104114
test('Should see custom row render HTML', () => {
105-
const rtl = render(<Table columns={columnsWithRender} data={data} />);
115+
render(<Table columns={columnsWithRender} data={data} />);
106116

107-
expect(rtl.getAllByTestId('first-name')).toHaveLength(2);
117+
expect(screen.getAllByTestId('first-name')).toHaveLength(2);
108118
});
109119

110120
const columnsWithColRender: ColumnType<any>[] = [
@@ -120,9 +130,9 @@ const columnsWithColRender: ColumnType<any>[] = [
120130
];
121131

122132
test('Should see custom column render HTML', () => {
123-
const rtl = render(<Table columns={columnsWithColRender} data={data} />);
133+
render(<Table columns={columnsWithColRender} data={data} />);
124134

125-
expect(rtl.getAllByTestId('first-name')).toHaveLength(1);
135+
expect(screen.getAllByTestId('first-name')).toHaveLength(1);
126136
});
127137

128138
// to supress console error from test output

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,5 @@ export type TableAction<T extends DataType> =
124124
| { type: 'GLOBAL_FILTER'; filter: (row: RowType<T>[]) => RowType<T>[] }
125125
| { type: 'SEARCH_STRING'; searchString: string }
126126
| { type: 'GLOBAL_FILTER_OFF' }
127+
| { type: 'SET_ROWS'; data: RowType<T>[] }
127128
| { type: 'TOGGLE_ALL' };

0 commit comments

Comments
 (0)