0

I get an error when calling this.props.fetch() in the mySort method. this.props.mySort collects new data from the backend sorted by the respective column. The error is: Warning: Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state. this.props.fetch is now called in an infinite loop.

How can I fix this?

Best regards, Joachim

constructor(props) {

    super(props)
    let columns = [
        { field: "foo", header: "bar", sortable: true, sortFunction: this.mySort }
    ]
    this.state = {
        cols: columns
    }
    this.colOptions = []
    for (let col of this.state.cols) {
        this.colOptions.push({ label: ` ${col.header}`, value: col })
    }
}

mySort = (e) => {

    if (e.order === 1) {
        console.log("1")
        this.props.fetch({...)}
        } else {
...}
      }


render() {

let columnData = this.state.cols.map((col, i) => {

        return <Column className="columnheader" style={col.style} key={col.field} field={col.field}
            header={col.header} sortable={col.sortable} sortFunction={col.sortFunction} body={col.body} expander={col.expander} />
    })

return(
<DataTable value={fetchResults} >
{columnData}
</DataTable>
)
}
Joey85
  • 1
  • 1

2 Answers2

0

You shouldn't be doing a fetch from inside a render, and the way it is, seems it's being called when every single column is rendered causing multiple state updates resulting in an infinite loop

Instead, move the fetch to componentDidMount. And whenever the sort field is changed, handle the change event and sort the data client side and reset your data, so that the whole table is already sorted and can be rendered at once. If the data is huge and needs the server to sort it for whatever reasons, again handle the refetch in the change event, and set the entire sorted data into state at one go.

Something like,

componentDidMount(){
  // fetch the data
}

handleSortFieldChange(){
  /* sort client side and -> setState()
  or fetch again and setState()*/
}
Karthik
  • 114
  • 2
  • 11
  • Right now I'm not storing the column data in state but in Redux store. The component receives the fetchResults as props in render() for further processing. So you mean I should store the data in state and change the state when clicking on sort to change the state and render this data inside the dataTable? – Joey85 May 17 '19 at 07:31
  • You can also just store the sort field into state, and sort the data real-time based on it if it's not too performance hindering. `handleSortFieldChange(){ // set sort field into state }` `sortData(data){ // your sort function }` `render(){ const sortedData = sortData(this.props.data) // map over this sorted data instead }` But do note that this would mean that the data is sorted every time the component rerenders even if there wasn't a change to the sort field. So I suggest if the data is huge, u create an action which updates your redux state with the sorted data. – Karthik May 17 '19 at 07:47
  • Yea, the data is very huge (up to millions of entries) and thats why it need to be sorted in the backend. So now I would simply change the sortField in the state and rerender if it changes? – Joey85 May 17 '19 at 08:09
  • In that case where backend needs to sort it, instead of storing the sortfield and sorting client side, you can refetch with the new sort field in the change handler whenever sort field changes and dispatch an action to update your redux store. That way whenever you map over your props, it'll always have updated data since it comes out of your store which has just updated with the new sort order. However you do it, the flow stays the same, only act upon changes and don't call set states from your render – Karthik May 17 '19 at 08:20
  • But I think the problem still is that the sortFunction is called inside render() here let columnData = this.state.cols.map((col, i) => { return }) – Joey85 May 17 '19 at 08:24
  • And you wrote that the event handler should dispatch whenever the sortField changes. But how do I check this if I do not put it in state? – Joey85 May 17 '19 at 08:43
0

I changed the sortFunction this way:

mySort = (e) => {
    if (e.order === 1 && e.field !== this.state.sortField) {
        this.setState({
            sortField: e.field
        },
            this.props.fetchSearchResults({
               ...
            }))
    } else if (e.order === -1 && e.field !== this.state.sortField) {
        this.setState({
            sortField: e.field
        },
            this.props.fetchSearchResults({
               ...
            }))
    }
}

Now, there is no infinite loop but the error stays the same.

Joey85
  • 1
  • 1