Passing AgGrid context from a functional React component - reactjs

I have a component that displays a table using AgGrid, and the data that is displayed comes from a Redux selector.
I want to render a cell in the table that has a button, which will then perform an action based on the row data.
The primary issue I have, is that when I pass a callback function to the button in the cell renderer, the row data is not populated when it gets called in the parent component. I believe that I need to pass the proper context to the cell renderer so that when it calls the function from the parent component, all of the data is present. However, please correct me if this is incorrect. However, I'm not sure how to properly pass the context given that all of this is happening from a functional component.
Example:
https://codesandbox.io/s/aggrid-redux-context-y49fd
Click on the "Set Row Data" button, which will make the button in the rows appear. Clicking the button will then print out the row data, which will be empty.
I need a way to be able to access the row data from the cell renderer.

Dirty solution
Try to bind this to onExecute when you are setting it to the cell render params:
cellRendererParams: { onExecute: onExecute.bind(this) }
Do you need to access data of all rows, or only single row that the current cell render is rendering? If you need data of the current row only, the AgGrid has already it in props, you can acces it in this.props.data in your cell renderer component.

Related

React ag grid, dispatching action to store on cell value changed rerenders whole grid

I need to update store when checkbox is clicked and i dispatch action with some row ids to use later, problem is grid gets rerendered and checkbox become unchecked again. I put dispatch in column definition
Do you maybe know how to solve this?

react-window saves state of deleted row

here is my problem.
I am using react-window to render large tables. Each row has its own local state. After I delete a row, the next row moves up and gains the state of the deleted row (this how it looks in my app).
Is there a workaround for this problem? Can i have local state for each row with react-window?
codesandbox example | gif how it works
There is a fundamental issue here - react-window will dynamically render, unmount and rerender components. So if you want data persisted across re-renders - you must pass the count via props and a function to change it. Store the data with the item data itself.
I will try and show a working demo of that soon ,but look at this to understand yet another problem happening with this code: https://codesandbox.io/s/react-window-row-state-problem-mmukt
I have edited the size to be 150 instead of 50, this leads to the window getting a scrollbar. Now, try and click on "two" multiple times. This will increase the count. Next, scroll to bottom and go back up. You'll see that the count is lost.
This is because of the way react-window mounts and unmounts components.
To fix this in your original code, I made the following modifications:
1. Move count/active state to parent.
2. Pass the updateCount function to TableRow.
Essentially, the TableRow is now a pure component :)
Here is the link: https://codesandbox.io/s/react-window-row-state-problem-uzsdl
Hope this helps.
In a nutshell, you can't. The issue is that, when you delete an item, the same component that was used previously for it will be used to render the item after it (so if you delete the 2nd item, the 3rd item will use the Row from the old 2nd element). It will maintain that item's state. If you add a useEffect to detect that the item changed, then you break everything after it (since everything is bumped up one, all of the items after the deleted item will reset their state. You don't have access to the sibling component's state, so you have no way to propagate the state.
You have a few options here:
Add the selection to the properties of the item, and provide a way to update the item.
Make the selection state part of the App component's state, and pass it down to the component so it can render appropriately.
I'll also add that you probably don't want to map over your presumably large list of items every render like you are now. It looks like you are doing this to expose deleteItems. I would recommend something more like this:
<FixedSizeList
height={500}
width={300}
itemCount={items.length}
itemSize={50}
itemData={{items, deleteItem}}
>
{Row}
</FixedSizeList>
Then your Row component's data will have both the items array and the deleteItem function. If you maintain your selected rows state in App, you easily extend this to pass the selected state and modification functions down to your Row component.

Using shouldComponentUpdate in a child component appears to be breaking state in parent component?

I have adapted this example from the material-ui table component example from the docs. In the provided example, rows can be selected, in which case the checkbox for that row will be checked. The problem with the example implementation is that when a change is made to any row, all of the rows will be re-rendered, even though only one of them has changed. This works fine as long as the number of rows is quite small but quickly degrades when rendering more rows.
As an attempted fix for this, I tried to implement shouldComponentUpdate in my Row components, to check if the row data (via the 'name' property), or the isItemSelected prop has changed (I ignored the other props as the callback function props will always be considered to have changed on each render). For some reason, this totally breaks my selected state in the parent Table component.
Here is my example, highlighting the issue: table-bug-example. As is, this reflects the example provided in the docs. You can see the lag issues if you set the rows per page drop down to a higher number. You can uncomment my shouldComponentUpdate implementation in the Row Component, to see how the state breaks in the Table component, when using shouldComponentUpdate in the children.
Expected Flow:
parent state keeps track of selected rows
clicking on row updates parent state
parent passes isSelected prop to child rows
row component checks to see if isSelected has changed, and re-renders only if this prop has changed
I have been struggling with this for several hours and can't for the life of me figure out what is wrong. I've also tried using React.memo, as well as different implementations of the setSelected state in the table component (I was previously using a dictionary to keep track of the selected rows, but for now I've left the default implementation provided in the material-ui docs, to minimize any issues introduced in my code).
Might anyone happen to know what is going on here?
When you used your custom shouldComponentUpdate what happened you "saved" the old version of handleClick inside of your custom MyRow, and since handleClick is not a pure function(it is using previous selection to determine prev selection state) it was always reading the wrong state.
For example you have 2 rows (row1 and row2). On initial render selection is : [], and the both render with the version of handleClick that has captured selection as []. You click on row1, it will rerender since its isItemSelected prop has changed, but row2 will not since your shouldComponentUpdate returned false. That means when you click on row2 it will use the handleClick from the first render wich had the selection as [] and it will uncheck row1 selection. There is no magic mechanism that binds selection, it all uses javascript context capturing.
Thats why custom shouldComponent is very dangerous. I would recommend using MyRow as a PureComponent (no need to use React.memo, you can just extend PureComponent) and transform handleClick inside table so it doesnt change (doesnt depend on current selection). Something like this: https://codesandbox.io/embed/material-demo-i0yp2?fontsize=14&hidenavigation=1&theme=dark
Hope this helps.

how to clear selected checkboxes programatically from parent component

I have used the following component in react,
https://www.npmjs.com/package/react-multiselect-checkboxes
I want to clear selected checkboxes because I have to recreate it with new options from another dropdown change event.
So is there any way from where I can clear selected checkboxes from parent component when another dropdown is changed
This is for react
The author of the libarary suggest that its behavior is based on react-select
Have you tried to use value prop?
see https://github.com/JedWatson/react-select#controllable-props
Additionally if you want to manipulate values in parent component you should use onChange callback then and store it somewhere (I assume state will be best place)

React checkbox component: Where should I keep state changes?

In react-table, I've made a custom drop-down-menu component that appears when user clicks on a header of a column.
When user clicks on the option "Choose columns", a modal appears with checkboxes options where user can select which columns to show or hide.
This modal with the checkboxes options is in the drop-down-menu component. The problem is I can not figure out which is the best way to handle state changes. Should I keep state changes on both components (table component and drop-down-menu component)? Should I use redux for that? I'm going to use many tables, so the total number of columns will be very big. I'm really confused about all this.
You should have one source of truth. As the table will need this information, it should be saved in the table and passed to the drop-down-menu component.
Checkout this codesandbox example.
Well if you want to make your checkbox reusable component, which you should, then you will have to keep the state in your checkbox component and expect an onChange event handler from wherever you want to use that checkbox component.

Resources