Skip to content

Allow ReorderCell to work in React v19 #745

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 27, 2025
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions src/plugins/ResizeReorder/ReorderCell.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,13 +240,30 @@ class ReorderCell extends React.PureComponent {
contents: this.cellRef.current,
};

ReactDOM.render(
// Since we're effectively rendering the proxy in a separate VDOM root, we cannot directly pass in our context.
// To solve this, we use ExternalContextProvider to pass down the context value.
// ExternalContextProvider also ensures that even if our cell gets unmounted, the dragged cell still receives updates from context.
// Since we're effectively rendering the proxy in a separate VDOM root, we cannot directly pass in our context.
// To solve this, we use ExternalContextProvider to pass down the context value.
// ExternalContextProvider also ensures that even if our cell gets unmounted, the dragged cell still receives updates from context.
const proxy = (
<ExternalContextProvider value={this.context}>
<DragProxy {...this.props} {...additionalProps} />
</ExternalContextProvider>,
</ExternalContextProvider>
);

if (this.props.__useReactRoot) {
const flushSync = ReactDOM.flushSync || ((fn) => fn()); // ReactDOM.flushSync doesn't exist in older versions of React
// flushSync is required to ensure that the drag proxy gets mounted synchronously in newer version of React
flushSync(() => {
const root = this.props.__useReactRoot(this.getDragContainer());
this.dragContainer.root = root;
root.render(proxy);
});
// we consider our cell to be in a reordering state as soon as the drag proxy gets mounted
this.setState({ isReordering: true });
return;
}

ReactDOM.render(
proxy,
this.getDragContainer(),
// we consider our cell in a reordering state as soon as the drag proxy gets mounted
() => this.setState({ isReordering: true })
Expand Down Expand Up @@ -287,7 +304,11 @@ class ReorderCell extends React.PureComponent {

removeDragContainer = () => {
// since the drag container is going to be removed, also unmount the drag proxy
ReactDOM.unmountComponentAtNode(this.dragContainer);
if (this.props.__useReactRoot) {
this.dragContainer.root.unmount();
} else {
ReactDOM.unmountComponentAtNode(this.dragContainer);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unmountComponentAtNode also doesn't exist anymore in React v19.

}

this.dragContainer.remove();
this.dragContainer = null;
Expand Down Expand Up @@ -363,6 +384,25 @@ ReorderCell.propTypes = {
* ```
*/
onColumnReorderEnd: PropTypes.func.isRequired,

/**
* HACK to make this plugin work in a React v19 environment by letting the client pass the `createRoot` function from `react-dom/client`.
*
* Example usage:
* ```
* import { createRoot } from 'react-dom/client';
*
* const reorderCell = (
* <ReorderCell
* __useReactRoot={createRoot}
* />
* ```
*
* See https://github.com/schrodinger/fixed-data-table-2/issues/743) for more information.
*
* @deprecated This'll be removed in future major version updates of FDT.
*/
__useReactRoot: PropTypes.func,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we just call this something very explicit like __react19RootCreator so it's clear we're asking you to just pass in the createRoot API directly

};

export default ReorderCell;