componentDidUpdate is one step behind the actual value in the setState - reactjs

I'm using React and chartJs to create some basic charts for a dashboard.
I want to implement a onClick functionality which will take the clicked element's data and update it in a AgGrid table.
I managed to do that but it appears that I have one problem: Whenever I click one element, it updates the values from the previous clicked element.
I understand that it has to do with the fact that setState is async and does not update at the moment when I click an element.
Any ideas?
below is my code:
handleChartClick = (element) => {
if (element[0] !== undefined) {
const { datasets } = element[0]._chart.tooltip._data;
const datasetIndex = element[0]._datasetIndex;
const dataIndex = element[0]._index;
const dataLabel = element[datasetIndex]._chart.data.labels[dataIndex];
const value = datasets[datasetIndex].data[dataIndex];
//alert(`${dataLabel}: ${value}`);
this.setState({
tabledata: {
columnDefs: [{ headerName: 'Service name', field: 'service', sortable: true, filter: true, resizable: true },
{ headerName: 'Running times', field: 'times', sortable: true, filter: true, resizable: true }],
rowData: [{ service: dataLabel, times: value }]
}
}, () => {});
}
}
In the Child class:
componentDidUpdate() {
this.state.tabledata = this.props.tabledata;
}
Extra: I am using classes for the definition of chart Components and the App.
/// Later Edit:
Found the problem, when i was instantiating my AgGrid, instead of using this.props.smth, I was using the this.state.smth (the problem was that at the current point, the state has not been modified yet and it was referencing to old values).

Related

Ant Design table pagination inconsistent after changing page and subsequent data change

Using antd 4.22.8 with react 18.2.0 (cra). Typescript code ahead
I'm using this code to fetch the data I need to show
const [pagination, setPagination] = useState<TablePaginationConfig>({
current: 1,
pageSize: 10
});
const [sort, setSort] = useState<SorterResult<FOO>>();
const [searchString, setSearchString] = useState<string>();
const [{ data, loading, error }, refetch] = useAxios<FOO[]>({
url: '/endpoint',
params: { skip: ((pagination.current ?? 0) - 1) * (pagination.pageSize ?? 0), take: pagination.pageSize, sortField: sort?.field, sortDirection: sort?.order, search: searchString }
});
const onTableChange: TableProps<FOO>['onChange'] = (pagination, _filters, sorter) => {
setPagination(pagination);
setSort(sorter as SorterResult<FOO>);
};
and this is how the data is shown
<Input.Search placeholder="Search" allowClear onChange={e => setSearchString(e.target.value)} />
<Table
rowKey={record => record.id}
loading={loading}
columns={[
{
title: 'ICCID',
dataIndex: 'id',
sorter: true
},
{
title: 'Name',
dataIndex: 'name',
sorter: true
}
]}
dataSource={data?.data}
pagination={{ position: ['topRight', 'bottomRight'], total: data?.count ?? 0, ...pagination }}
onChange={onTableChange}
/>
The problem arises with the pagination in this component. Imagine these 2 use case:
You never changed page: I can use the search field to perform some search. Pagination changes correctly reflecting the data that came from the endpoint (different page count, etc...).
I've changed the page: on the first load the endpoint returns quite lot of record and you move to, say, page 4 clicking on the relative button on the paginator component. Then perform a search: data returns correctly but pagination does not reflect changes anymore. Page count is still pre-search, and so is the selected page, but not showing page 4 of the freshly searched dataset, but page 1.
What I'd expect is the pagination component is reset itself after dataset changes, as it does when changing pages or sort

ag-grid react how to return value from external popup component

We're trying to use ag-grid to display and edit different types of data, for example a color. We have a react component that displays a set of colors for the user to choose from, with OK and CANCEL buttons that close the dialog (it's a MUI Dialog component) and calls a callback function prop with the selected color (if OK clicked).
We are able to get this dialog to display from the ag-grid cell, but can't figure out how to get the color returned to the cell. Currently the color dialog is defined as
const ColorChooser = ({initialColor, callback}) => {
const [color, setColor] = useState(initialColor);
const [open, setOpen] = useState(true);
and the OK button handler is simply
const okHandler = () => {
if (callback) {
callback(color);
}
setOpen(false);
}
where the open state opens / closes the MUI Dialog.
In another component we are able to display the dialog from the ag-grid based on the 'type' of the data in the grid cell:
//
// Return the appropriate editor based on the cell contents
const selectEditor = (params) => {
if (params.data.dataType === 'string') {
return (
{
component: 'agTextCellEditor',
params: params,
}
)
}
else if (params.data.dataType === 'color') {
return (
{
component: ColorChooser,
params: params,
popup: true,
popupPosition: 'under'
}
)
}
}
const [columnDefs] = useState([
{ field: 'property', lockPosition: 'left', resizable: true, sortable: true, flex: 1 },
{ field: 'value', editable: true, flex: 1, cellEditorSelector: selectEditor, cellRendererSelector: selectRenderer }
]);
and this is where we're stumped. The color dialog displays but we can't figure out how to get the selection back to the cell when the OK button is clicked.
In case it's not obvious I'm fairly new to react and ag-grid, apologies if this is too elementary. Thanks!

How to set the enable and disable value to table column switch button in react js

Im using class component in my application.
I want to set the value to the table column button. and i fetch the value from backend
it was an array response. Array values auto mapped by my table column key.
Ex: This was my table column and it was auto mapped by fetch response name. fetch response name
is "description".
{
title: 'Description',
dataIndex: 'description',
key: 'description',
sorter: true
},
But problem is how auto mapped to the response name to switch button I try but I can't.
My Switch column:-
{
title: 'Action',
dataIndex: 'enabled',
key: 'enabled',
render: (text: any, record: any) => (
<div>
<Tooltip title="Enable / Disable" color={'#d31145'}>
<Switch autoFocus checkedChildren="Enable" unCheckedChildren="Disable" className={'customswitch'} onChange={checked => this.changeSwitch(checked,record.proId)}/>
</Tooltip>
</div>
),
}
I need to know how to set the fetch value to switch button in react class component.
I fetch All data from using this code.
fetch = (params: any = {}) => {
let providerConfigureDto: ProviderConfigureDto = {...this.state.providerConfigureDto};
this.setState({isLoading: true});
providerConfigureService.getAllProviders(providerConfigureDto).then(res => {
console.log(res.data.content)
const pagination: any = {...this.state.pagination};
pagination.total = res.data.total;
this.setState({
isLoading: false,
total: res.data.totalElements,
providerConfigures: res.data.content,
providerConfigureDto: providerConfigureDto,
pagination
});
})
providerConfigureDto.page = 0
};
ProviderConfigureDto has only sorter option and pagble option only.
I fetch from array from back end and i create a array in state. then i set the array to table datasouce
Like this :-
providerConfigures:Array<any>,
That's all please help me for that.

Using custom component in ag-grid cell render

I am trying to use a custom component in a cell in ag-grid, if i use a standard html component it works but not if i try to use a custom react component
Below code does not works
TABLE_COLUMNS = [
{
headerName: '', field: 'remarks', cellRendererFramework: (params) => {
return <div>
<SpinningWheel height={100}/>
</div>
}
}]
But below code works fine
TABLE_COLUMNS = [
{
headerName: '', field: 'remarks', cellRendererFramework: (params) => {
return <div>
<button>push me</button>
</div>
}
}
Everything seems to be working fine for me. I have created a similar component wrapped inside a div in a plunker from one of their examples and it is working as expected. Look for the following in columnDefs in index.js file.
{
headerName: "Child/Parent",
field: "value",
cellRendererFramework: (params) => <div><SpinningWheel {...params} name="Spinning Wheel"/></div>,
colId: "params",
width: 180
}

How to separate UI and application state in Redux

When writing a react-redux application, I need to keep both application and UI state in the global state tree. What is the best approach to design it's shape?
Lets say I have a list of todo items:
{
items: [
{ id: 1, text: 'Chew bubblegum' },
{ id: 2, text: 'Kick ass' }
]
}
Now I want to let the users select and expand the items. There are (at least) two options how to model the state shape:
{
items: [
{ id: 1, text: 'Chew bubblegum', selected: true, expanded: false },
{ id: 2, text: 'Kick ass', selected: false, expanded: false }
]
}
But this is mixing the UI state (selected and expanded) with the application state. When I save the todo list to the server, I want to save just the application state, not the UI state (in real-world app, UI state can contain state of modal dialogs, error messages, validation status etc).
Another approach is to keep another array for the UI state of the items:
{
items: [
{ id: 1, text: 'Chew bubblegum' },
{ id: 2, text: 'Kick ass' }
],
itemsState: [
{ selected: true, expanded: false },
{ selected: false, expanded: false }
]
}
Then you have to combine those two states when rendering an item. I can imagine that you can zip those two arrays in the connect function to make rendering easy:
const TodoItem = ([item, itemState]) => ...;
const TodoList = items => items.map(item => (<TodoItem item={item} />));
export default connect(state => _.zip(state.items, state.itemsState))(TodoList);
But updates to state can be painful, because items and itemsState must be kept in sync:
When removing an item, corresponding itemState must be removed.
When reordering items, itemsState must be reordered too.
When the list of todo items is updated from the server, it is necessary to keep ids in the UI state and do some reconciliation.
Is there any other option? Or is there any library that helps keeping the app state and UI state in sync?
Another approach inspired by normalizr:
{
ids: [12,11], // registry and ordering
data: {
11: {text: 'Chew bubblegum'},
12: {text: 'Kick ass'}
},
ui: {
11: { selected: true, expanded: false },
12: { selected: false, expanded: false }
}
}
I'm currently looking at this myself for a side project. I'm going to approach it similar to Rick's method above. The data{} serves as the source of truth and you use that to push local ui changes into (reflecting the most current state). You do need to merge the data and ui together before render, and I myself have tried that in a few places. I will say, as far as keeping in sync, it shouldn't be too bad. Basically, whenever you save/fetch data, you're updating data{} and clearing out ui{} to prepare for the next use case.

Resources