When the React BryntumGrid component is mounted, the data (which is managed in Mobx State Tree) is filled in the config. However, when that state changes, the grid is not updated.
How can I force such an update? I tried reloading the dataset with store.loadData() but the view isn't updated.
There shouldn't be anything else needed just binding the data property to your state. The following App.js can replace Grid basic example and it works as expected. The grid starts populated and is cleared after 3s:
I'm using a tree grid, and when I'm updating the array, the column renderer is running again, but the UI isn't updating. It's like the UI and the data are out of sync.
Also, I'm getting this in the console:
BryntumGridComponent development warning!
"columns" is a static config option for component constructor only. No runtime changes are supported!
Please check integration guide: https://www.bryntum.com/docs/grid/#guides/integration/react.md
Try to toggle the admin status of a user. Note that the array is correctly updated, but the update is not shown in the UI. In other words, "Yes" doesn't turn into "No" and vice versa.
Last edited by Yamo93 on Fri Apr 23, 2021 10:41 am, edited 1 time in total.
Re warning about columns: columns property is config-only what means that it can be set only once on the grid instantiation. Any runtime attempts to change columns are ignored at runtime with the above warning. The array passed as config is transformed to ColumnStore so if you need to alter columns you need to treat this property as ColumnStore.
Re data: Normally, we do not pass the whole data object to the grid when only one record changes but we just update the underlying record. Therefore, your admin toggle button can look simple like this:
Okay, thanks for the explanation. I managed to update the UI by updating the grid store manually. Updating that record wasn't as easy as in your example, because I had to recursively find that record in the tree structure and update the fields.
The conclusion is that the BryntumGrid component can't sync the data with the UI on a record level, but only on an array level. So if a property in a record changes, that isn't reflected in the UI automatically.
This will be cumbersome though, because it means that I have to manage two states: the Mobx/React state and the Grid store state.
I really hope that this will be dealt with in a newer version of your React wrapper, so that the data is automatically in-sync with the UI.
Okay, thanks for the explanation. I managed to update the UI by updating the grid store manually. Updating that record wasn't as easy as in your example, because I had to recursively find that record in the tree structure and update the fields.
The conclusion is that the BryntumGrid component can't sync the data with the UI on a record level, but only on an array level. So if a property in a record changes, that isn't reflected in the UI automatically.
When you change a record field it always updates the grid row (if store events are not suspended).
This will be cumbersome though, because it means that I have to manage two states: the Mobx/React state and the Grid store state.
The Bryntum Grid has the fully functional data layer called the store. You can think of the store as of a state manager provided by Bryntum. You can load/save the data from/to the server directly. You can instantiate a new store globally, load data in it, and reuse in many components. If you're going to have another data layer (like component state), then you'll have to sync the data manually. In our examples we show how to load the data to the store manually. So the array of "local" data is set to the store. Technically, when you pass an array of objects, the grid store creates an array of records (see Model), it sets the Id, default fields, does some preparation. So after you load the data you can think of it as of records, not just simple objects. And then when the react state is updated, it sets a new array of data to the store. There is a config to treat the data as completely new dataset, or try to merge the data with the current dataset: https://www.bryntum.com/docs/grid/#Core/data/Store#config-syncDataOnLoad
Back to the code you provided, there is a problem with it. You tried to avoid mutation of the array by having a copy of the array elements at the first line. But this is an array of objects, and objects should be immutable too!
As a side note, column renderer argument (renderData) is an object that contains many other cell/UI related info, which you don't need to pass to the toggle handler. I would recommend to pass only record. And whenever it is possible use getter instead of accessing fields via "data", so:
But this is not recommended approach. It's better to use setter on the record field to change data, and if you need, update the component state. Note, store.data holds "the raw original data", when store.records or allRecords hold an array of records to be used by the store. You can take a copy of the record data to pass to the component state.
const toggleAdmin = (record) => {
// This will update the data in the Grid Store
record.isAdmin = !record.isAdmin;
// This will sync the Grid Store with the Component State
const users = userGridRef.current.gridInstance.store.records.map(r => ({ ...r.data }));
setCustomGridData(users);
};
More over, if you edit a cell value, you might want to sync it with the component state too. For that you can add a listener to update the state:
useEffect(() => {
userGridRef.current.gridInstance.store.on({
update() {
// This will sync the Grid Store with the Component State
const users = userGridRef.current.gridInstance.store.records.map(r => ({ ...r.data }));
setCustomGridData(users);
}
})
}, []);
And therefore simplify the toggle handler to:
const toggleAdmin = (record) => {
// This will update the data in the Grid Store
record.isAdmin = !record.isAdmin;
};
As a side note, changing the record field will already update the grid view. But when you set the new array to the component state, since it's bound to the store data, the grid data will be reloaded. Make sure syncDataOnLoad is true (default).