I am using and enjoying react-tables with me react/redux project, to which I recently added server-side pagination, sorting and filtering. The main issue is that I don't want nor need to make requests to my API as often as they are generated by onFetchData (typically, onKeyUp events on filters) and that puts a strain on our server. I have tried adding a 'lastQuery' time flag to my store in order to only fetch data if the last time I did was, say, 400ms ago, but that systematically requires a last fetchData action after the last to get the data, otherwise it never loads (ex: write a word on a filter, and it will not filter if the entire word was written in less than 400ms).
There is a very similar plug-in for the datatables (non-react) library, and I was wondering if someone would be interested in adding that functionality.
If you have a workaround, do tell me!
Thank you very much,
Alessandro
Maybe lodash's debounce function can solve your use case?
I was looking for this functionality as well. I'm only using client side filtering, but it is still noticeably slow if you type quickly. _.debounce looks like it would solve this problem, but I think it is a common enough use case that it should be implemented by this library.
The library is very lightweight and I don't think it should implement debounce for several reasons. Firstly, it would require reliance on a specific debounce library. Secondly, deciding when it should and shouldn't be used will complicate the interface to the component (I have already found lots of places where I would use and where I wouldn't).
All my debounce is at a higher level than react-table.
I'm using a filterable ReactTable that queries the server for both filtering AND pagination. If I add debounce to my handleFetch function, it applies debounces to both filtering and pagination. Pagination should be "debounce-less." What is the strategy for handling this?
In my mind, there should be an optional, dedicated prop that filter can use for processing.
E.g.:
<ReactTable filterable
onFetchData={handleFetch}
onFilterData={handleDebouncedFetch}
/>
onFetchData - handles fetching for filtering
onFilterData - handles fetching for pagination, sorting, etc
@derekcannon If I were to require that, I'd just move my debounce higher and make the switch between them in the single callback. I take your point, but if that is the best way to go, then there would be a good argument for having a separate call for each of the different things (paging, filtering, sorting, expanding, etc.). Not saying that is "wrong" but it sort of would "break" a lot of existing implementations so is probably best left until a re-design of the underlying system.
Even so, a use can probably click the page change faster than the server can return the data - so I (personally) would probably debounce that as well to abort unnecessary server calls - YMMV.
Thanks for the reply, Gary. I have attempted to implement a conditional switch but it does not work. I'm sure I'm doing something wrong here. Is this how you'd approach it:
EDIT: I read the documentation a little more about setState.. so I just converted this into an instance variable and now everything works. I've updated the example for anyone wondering how to achieve this.
class SomeComponent extends Component {
constructor() {
super();
this.state = {
data: [],
pages: null,
};
this.filtering = false;
this.onFilteredChange = this.onFilteredChange.bind(this);
this.fetchStrategy = this.fetchStrategy.bind(this);
this.fetchData = this.fetchData.bind(this);
this.fetchDataWithDebounce = _.debounce(this.fetchData, 1500);
// ^ debounced version of "fetchData"
}
fetchStrategy(tableState) {
if(this.filtering) {
return this.fetchDataWithDebounce(tableState)
} else {
return this.fetchData(tableState);
}
}
onFilteredChange(column, value) {
this.filtering = true; // when the filter changes, that means someone is typing
}
fetchData(tableState) {
this.filtering = false // we've arrived either debounced or not, so filtering can be reset
};
// fetch api...
}
render() {
return (
<ReactTable
data={this.state.data}
pages={this.state.pages}
onFetchData={this.fetchStrategy}
onFilteredChange={this.onFilteredChange}
filterable />
);
}
}
@derekcannon you're my hero
Thanks for the reply, Gary. I have attempted to implement a conditional switch but it does not work. I'm sure I'm doing something wrong here. Is this how you'd approach it:
EDIT: I read the documentation a little more about setState.. so I just converted this into an instance variable and now everything works. I've updated the example for anyone wondering how to achieve this.
class SomeComponent extends Component { constructor() { super(); this.state = { data: [], pages: null, }; this.filtering = false; this.onFilteredChange = this.onFilteredChange.bind(this); this.fetchStrategy = this.fetchStrategy.bind(this); this.fetchData = this.fetchData.bind(this); this.fetchDataWithDebounce = _.debounce(this.fetchData, 1500); // ^ debounced version of "fetchData" } fetchStrategy(tableState) { if(this.filtering) { return this.fetchDataWithDebounce(tableState) } else { return this.fetchData(tableState); } } onFilteredChange(column, value) { this.filtering = true; // when the filter changes, that means someone is typing } fetchData(tableState) { this.filtering = false // we've arrived either debounced or not, so filtering can be reset }; // fetch api... } render() { return ( <ReactTable data={this.state.data} pages={this.state.pages} onFetchData={this.fetchStrategy} onFilteredChange={this.onFilteredChange} filterable /> ); } }
Thank you sooo much!
Most helpful comment
Thanks for the reply, Gary. I have attempted to implement a conditional switch but it does not work. I'm sure I'm doing something wrong here. Is this how you'd approach it:
EDIT: I read the documentation a little more about setState.. so I just converted this into an instance variable and now everything works. I've updated the example for anyone wondering how to achieve this.