'Using React class component returns Invalid hook call error
I am writing a simple class component that reorders some rows. For some reason I am getting the following error:
Invalid hook call. Hooks can only be called inside of the body of a function component.
And I am really puzzled because I am not using any hooks, just setState. Why does this error occur even though I am not using any hooks and how can I fix it? Here is my main.tsx code:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Grid, GridColumn as Column } from '@progress/kendo-react-grid';
import { DragAndDrop } from '@progress/kendo-react-common';
import { DragHint } from './drag-hint';
import { DraggableRow } from './dragable-row';
import { SelectionCell } from './selection-cell';
import products from './products.json';
import { Product } from './interfaces';
export let ReorderContext = React.createContext<{
reorder: (dataItem: Product, direction: 'before' | 'after' | null) => void;
dragStart: (dataItem: Product) => void;
dragEnd: (dataItem?: Product) => void;
}>({ reorder: () => {}, dragStart: () => {}, dragEnd: () => {} });
export let SelectionContext = React.createContext<[Product[], any]>([
[],
() => {},
]);
export let IsSelectedContext = React.createContext<boolean>(false);
export const DragHintContext =
React.createContext<React.RefObject<HTMLElement> | null>(null);
export let GridContext = React.createContext<React.RefObject<Grid> | null>(
null
);
let grid = React.createRef(null);
let hint = React.createRef();
null;
class App extends React.Component {
state = {
gridData: products,
selection: [],
activeItem: null,
};
reorder(dataItem: any, direction: 'before' | 'after') {
if (this.state.activeItem === dataItem) {
return;
}
let reorderedData = this.state.gridData.slice();
reorderedData = reorderedData.filter(
(item) =>
!this.state.selection.some(
(selectedItem) => selectedItem.ProductID === item.ProductID
)
);
let nextIndex = reorderedData.findIndex((p) => p === dataItem);
reorderedData.splice(
Math.max(nextIndex + (direction === 'before' ? 0 : 1), 0),
0,
...this.state.selection
);
this.setState({ gridData: reorderedData });
}
dragStart(dataItem: any) {
this.setState({ activeItem: dataItem });
}
dragEnd() {
this.setState({ activeItem: null });
}
render() {
return (
<GridContext.Provider value={grid}>
<DragHintContext.Provider value={hint}>
<ReorderContext.Provider>
<SelectionContext.Provider value={[this.state.selection]}>
<DragAndDrop>
<Grid
ref={grid}
style={{ height: '400px' }}
data={this.state.gridData}
dataItemKey={'ProductID'}
rowRender={(row, rowProps) => (
<DraggableRow elementProps={row.props} {...rowProps} />
)}
>
<Column title="" width="80px" cell={SelectionCell} />
<Column field="ProductID" title="ID" width="60px" />
<Column field="ProductName" title="Name" width="200px" />
<Column field="Category.CategoryName" title="CategoryName" />
<Column field="UnitPrice" title="Price" width="80px" />
<Column field="UnitsInStock" title="In stock" width="80px" />
</Grid>
<DragHint
ref={hint}
portal={grid}
className="k-card"
style={{
display: this.state.activeItem ? undefined : 'none',
}}
>
{this.state.activeItem && this.state.activeItem.ProductName}
{this.state.selection.length > 1 && (
<div
style={{
position: 'absolute',
pointerEvents: 'none',
bottom: 0,
right: 0,
background: 'red',
padding: 8,
width: 32,
color: 'white',
borderRadius: '50%',
transform: 'translate(50%, 50%)',
}}
>
{this.state.selection.length - 1}
</div>
)}
</DragHint>
</DragAndDrop>
</SelectionContext.Provider>
</ReorderContext.Provider>
</DragHintContext.Provider>
</GridContext.Provider>
);
}
}
ReactDOM.render(<App />, document.querySelector('my-app'));
And here is a reproducible example that contains the rest of the components as well:
https://stackblitz.com/edit/react-ms8hzy-wpfjcb?file=package.json
Solution 1:[1]
You are using React.useContext in your DraggableRow class component.(line 27 - 31)
My suggestion is to switch to functional components only. But if you want to use class based components I will refer you to this question which explains your problem.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | bguiz |
