React-table: Force React-table to reload

Created on 8 May 2018  Â·  20Comments  Â·  Source: tannerlinsley/react-table

What version of React-Table are you using?

6.8.0

What bug are you experiencing, or what feature are you proposing?

I'd like to be able to force the Component to reload so the 'onFetchData' handler would trigger again, or be able to reuse the function implemented inside the 'onFetchData'.

The context is that I have a function that add a new object in my data base, which should appear in the table, but it needs to update to do so. I can't just insert it my state.data since my backend alter the object.

It's my first project with React, maybe I'm missing a simple concept.

Use https://codesandbox.io/s/X6npLXPRW (by clicking the "Fork" button) to reproduce the issue.

https://codesandbox.io/s/olo47vwo89

Thank you for your time

Most helpful comment

OK, here it is for V6:

  • add a ref to react table
  • create a function for onFetchData that receives table 'state' which will call your data and set data and paging, etc
  • get state from ref.current.state after your edit and call your fetch function with it, the state updates in your fetch calls promise return will update the table just like when it calls onFetchData itself.

```class MyComponent extends React.Component {
constructor(props) {
super(props);
this.table = React.createRef();
this.fetch = this.fetch.bind(this);
}
render() {
return ref={this.table}
onFetchData={this.fetch}
...
/>;
}
fetch(state){
// make call -> then update state
}
onFinishedEditOrDelete(){
this.fetch(this.table.current.state);
}
}

All 20 comments

React refreshes based on properties on the component changing.

If you are using onFetchData you have to use this.setState to set a state variable with the data and then use that as the data prop for ReactTable. This is how 99% of React components work.

@gary-menzel Thanks for your answer, but it's not solving the problem.

Maybe I didn't explain the problem the correctly.

I have a custom component which wrappe a ReactTable component. React-Table is to retrieve my data on database in the backend.
My custom component also has a handler to add an object in my database and upon success, I notify my user by altering the state of the custom component.

The problem is, upon successful add of an object, the component ReactTable becomes outdated and does not refresh, even though I change the state of my custom component.

My apologies for not being clear enough on the first post and thank you for your time. :)

If you search these github issues you will see that many people have asked for a "refresh" function - and there is not going to be one added because it just isn't the way React works.

It's not the state of your custom component that needs to change - it is the properties that are being used by ReactTable. So, to get the data to update, you have to use this.setState to change the data prop in your wrapping components state. That is how "React" does updates - that is the simple concept that you have to wrap your head around.

Even more so, ReactTable stretches those concepts even further (so if it is your first project, trying to get ReactTable to work like other JS packages you may have used with something like jQuery will be a challenge and you'll just have to work through it until you "get it" - no shortcuts).

Finally, everyone coming from that "call a function to do something" approach wants to use onFetchData - I think it is unnecessary 99% of the time (and usually only needed when you have hundreds of thousands of records).

The codesandbox you supplied doesn't actually work (it gets compilation errors) so I was unable to see what your component architecture looks like. Feel free to post a "working" (aside from the problem you described) replacement.

Thank you, I was missing one point in React, the re render does not take effect on child components unless state changing.

Thank you for explaining this to me, now it works, following your instructions: when the creation succeed, I call my database to read the new object and manually add it to the data.

I was talking about the onFetchData because it's the one used in the example.

Thank you again for the great support.

Correct me if I am wrong. I think this only works when the length of data array has changed. If you just change one element in the array, for example, data[0].age = 3; then setState({data}), it will not update.

react-virtualized does provide a forceUpdate function to force the grid to update. It's useful because when the underlying data is changed frequently, we want to forceUpdate periodically (e.g. every second) instead of asynchronously (e.g. onUpdate).

@gary-menzel, earlier in this thread you responded with this:

"React refreshes based on properties on the component changing.
If you are using onFetchData you have to use this.setState to set a state variable with the data and then use that as the data prop for ReactTable. This is how 99% of React components work."

In my case I'm using redux for my data so I'm using this.props. vs this.state. In my testing it seems to make no difference which I use, but I'm having an issue where the state in ReactTable component is not updated...

I'm using redux to store multiple "views" of logging data, each view also stores the filtered object from table state based on what filters, if any are selected when that view is selected. If there are no filters set, filtered = []. When I render ReactTable, I pass this.props.filtered (from redux mapStatetoProps) in via filtered and defaultFiltered props so the table renders with the filters for that view.

The problem I'm having is that if I have a view that DOES have filters (table state.filtered NOT empty), then I create a new view that has filtered = [], the next render still shows the filters of the last view, which I consider "stale". The new data is displayed as expected, it's just the filters from the last view displayed.

Any thoughts on why that is, and how I can assure the new view/filtered object are reflected in the next render?

Thanks in advance,

Paul

@gary-menzel I do agree that in react it is expected that a refresh only happens when the props change. But the thing is even that is not enough for the ReactTable component.

Let's consider:

const data = [ { name: "record1"} , { name:"record2"}  ];
this.setState( { data } );

render () { return <ReactTable data={this.state.data} ... /> };

Now, just following your logic, it would be enough to say:

const newData = [... this.state.date];
this.setState( { data: newData } );

But that isn't enough to force a refresh. You actually need to ...

const data= this.state.data;
const newData = [];
for (const record of data) {
  const newRecord = {... record};
  newData.push(newRecord);
}
this.setState( { data: newData });

And while I can understand it from a technical point of view. Yes, I can imagine why it's supposed to be like that. But let's document it somewhere.

react-table owns state and hides it from us. thus, we can't simply "pass new data in" to get a refresh. my new data is a function of react-table's managed state.

thus, we at least need to some mechanism or prop to pass down into react-table to have it trigger it's data retrieval workflow. e.g. <ReactTable isDataStale />. such a prop being set perhaps kicks off onFetchData once, until that prop is cleared?

This state will be 💯% accessible, controllable and exposed in the next
major version of RT.

On Sat, Jan 5, 2019 at 5:16 PM Christopher Dieringer <
[email protected]> wrote:

again, react-table owns state and hides it from us. thus, we can't simply
"pass new data in" to get a refresh. my new data is a function of
react-table's managed state
.

thus, we at least need to some mechanism or prop to pass down into
react-table to have it trigger it's data retrieval workflow. e.g. isDataStale />. such a prop being set perhaps kicks off onFetchData once,
until that prop is cleared?

—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/react-tools/react-table/issues/955#issuecomment-451703916,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AFUmCbhvw29osxI8JO-fB-vypBzA1oqhks5vAUBUgaJpZM4T2RNL
.

@tannerlinsley is this accessible on master now?

This answer is only satisfactory if you happen to have the data entity that was saved to your data store. If you made a POST call to a server, and it saves data, and that data is manipulated on the back end, you need to be able to update the table with the new field from the store. If you are using the onFetchData functionality, you have no way of forcing the table to call that function without artificially setting some state data to manipulate the react elements. You can't separate the data call function from the table, because then you will not have the tables state and instance data that it passes to onFetchData. The concept that this control does not need a refresh because "that's not how React works" is just false.

@cfalone, you are correct in your use case which is the very use case that is being taken into heavy consideration for v7.

@lloydw Yes.

You are fast!
What is a decent workaround for this, I need to get some refreshes to work yesterday? :)

OK, here it is for V6:

  • add a ref to react table
  • create a function for onFetchData that receives table 'state' which will call your data and set data and paging, etc
  • get state from ref.current.state after your edit and call your fetch function with it, the state updates in your fetch calls promise return will update the table just like when it calls onFetchData itself.

```class MyComponent extends React.Component {
constructor(props) {
super(props);
this.table = React.createRef();
this.fetch = this.fetch.bind(this);
}
render() {
return ref={this.table}
onFetchData={this.fetch}
...
/>;
}
fetch(state){
// make call -> then update state
}
onFinishedEditOrDelete(){
this.fetch(this.table.current.state);
}
}

@cfalone Thank you so much for this.

A complementary piece to this that was helpful for me was that setState has a 2nd argument for a callback function to ensure that the fetch() call happens after the state change (if there are elements to your state that affect your fetch query).

So you can do:

this.setState({whatever state change}, this.fetch(this.table.current.state));

OK, here it is for V6:

  • add a ref to react table
  • create a function for onFetchData that receives table 'state' which will call your data and set data and paging, etc
  • get state from ref.current.state after your edit and call your fetch function with it, the state updates in your fetch calls promise return will update the table just like when it calls onFetchData itself.
  constructor(props) {
    super(props);
    this.table = React.createRef();
    this.fetch = this.fetch.bind(this);
  }
  render() {
    return <ReactTable
       ref={this.table}
       onFetchData={this.fetch}
       ...
    />;
  }
  fetch(state){
    // make call -> then update state
  }
  onFinishedEditOrDelete(){
     this.fetch(this.table.current.state);
  }
}

Legend! Wish I found this post about 7 hours ago!!

OK, here it is for V6:

  • add a ref to react table
  • create a function for onFetchData that receives table 'state' which will call your data and set data and paging, etc
  • get state from ref.current.state after your edit and call your fetch function with it, the state updates in your fetch calls promise return will update the table just like when it calls onFetchData itself.
  constructor(props) {
    super(props);
    this.table = React.createRef();
    this.fetch = this.fetch.bind(this);
  }
  render() {
    return <ReactTable
       ref={this.table}
       onFetchData={this.fetch}
       ...
    />;
  }
  fetch(state){
    // make call -> then update state
  }
  onFinishedEditOrDelete(){
     this.fetch(this.table.current.state);
  }
}

Man, you are a hero :D

Any update on how to do this in v7. Looked through the docs and I'm not seeing anything...

Been using redux and had the same issue, to force update of the component and to trick it that new set of data is being retrieved (get around the referential checks) I have resorted to recreating the data array by simply using JSON.parse() and JSON.stringify() before passing it to the action.

handleRemoveFile = id => {
    var files = this.props.download.files;
    _.remove(files, file => file.id === id);
    var newfiles = JSON.parse(JSON.stringify(files));
    this.props.setDownloadFiles(newfiles);
};

For now it works, really wishing to have a more decent way to force the reload/refresh.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Abdul-Hameed001 picture Abdul-Hameed001  Â·  3Comments

DaveyEdwards picture DaveyEdwards  Â·  3Comments

LeonHex picture LeonHex  Â·  3Comments

dilipsundarraj1 picture dilipsundarraj1  Â·  3Comments

monarajhans picture monarajhans  Â·  3Comments