I have a grid created using a React library that I want to fill with data with an API call once the user clicks on a button called Fetch Products. Currently, my grid does not get populated and I get this error when I debug it:
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'dataState')
and I am not sure why. Why isn't the grid populating properly and what else can I do? Here is my code:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Grid, GridColumn as Column } from '@progress/kendo-react-grid';
import { process } from '@progress/kendo-data-query';
import {
setExpandedState,
setGroupIds,
} from '@progress/kendo-react-data-tools';
const initialDataState = {
take: 10,
skip: 0,
products: [],
group: [
{
field: 'id',
},
],
};
const processWithGroups = (data, dataState) => {
const newDataState = process(data, dataState);
setGroupIds({
data: newDataState.data,
group: dataState.group,
});
return newDataState;
};
const fetchAllData = () => {
fetch(
'https://otp.metroservices.io/otp/routers/default/index/routes/uscalacmtarail:801/stops'
)
.then((response) => response.json())
.then((productsList) => {
const newDataState = processWithGroups(
productsList,
this.state.dataState
);
this.setState({
products: productsList, // update the data
result: newDataState, // update the procesed data
});
});
};
const FirstButton = () => {
return (
<div>
<button type="button" onClick={fetchAllData}>
Fetch Products
</button>
</div>
);
};
class App extends React.PureComponent {
state = {
dataState: initialDataState,
result: processWithGroups(initialDataState.products, initialDataState),
collapsedState: [],
products: [],
};
dataStateChange = (event) => {
const newDataState = processWithGroups(
this.state.products, // use the none processed data
event.dataState
);
this.setState({
result: newDataState,
dataState: event.dataState,
});
};
expandChange = (event) => {
const item = event.dataItem;
if (item.groupId) {
const newCollapsedIds = !event.value
? [...this.state.collapsedState, item.groupId]
: this.state.collapsedState.filter(
(groupId) => groupId !== item.groupId
);
this.setState({
collapsedState: newCollapsedIds,
});
}
};
// componentDidMount() {
// this.fetchAllData()
// }
render() {
const newData = setExpandedState({
data: this.state.result.data, // pass the proccessed data
collapsedIds: this.state.collapsedState,
});
return (
<div>
<FirstButton />
<Grid
style={{
height: '520px',
}}
resizable={true}
reorderable={true}
filterable={true}
sortable={true}
groupable={true}
data={newData}
onDataStateChange={this.dataStateChange}
{...this.state.dataState}
onExpandChange={this.expandChange}
expandField="expanded"
>
<Column field="id" filterable={false} title="ID" width="50px" />
<Column field="name" title="Name" />
<Column field="cluster" title="Cluster" filter="numeric" />
</Grid>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('my-app'));
CodePudding user response:
this.state.dataState
does not exist in fetchAllData
.
You need to pass the this.state.dataState
in App
to FirstButton
then to fetchAllData
. After all that, you can use that
CodePudding user response:
Put the functions inside the React.Component that require to interact with states and if needed to use something to the outside of the React.Component, pass the reference state. In your code, you can put your 'fetchAllData' function inside you React.Component and pass this as a prop to your FirstButton
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Grid, GridColumn as Column } from '@progress/kendo-react-grid';
import { process } from '@progress/kendo-data-query';
import {
setExpandedState,
setGroupIds,
} from '@progress/kendo-react-data-tools';
const initialDataState = {
take: 10,
skip: 0,
products: [],
group: [
{
field: 'id',
},
],
};
const processWithGroups = (data, dataState) => {
const newDataState = process(data, dataState);
setGroupIds({
data: newDataState.data,
group: dataState.group,
});
return newDataState;
};
// pass the fetchAllData function as a prop
const FirstButton = ({fetchData}) => {
return (
<div>
<button type="button" onClick={fetchData}>
Fetch Products
</button>
</div>
);
};
class App extends React.PureComponent {
state = {
dataState: initialDataState,
result: processWithGroups(initialDataState.products, initialDataState),
collapsedState: [],
products: [],
};
dataStateChange = (event) => {
const newDataState = processWithGroups(
this.state.products, // use the none processed data
event.dataState
);
this.setState({
result: newDataState,
dataState: event.dataState,
});
};
expandChange = (event) => {
const item = event.dataItem;
if (item.groupId) {
const newCollapsedIds = !event.value
? [...this.state.collapsedState, item.groupId]
: this.state.collapsedState.filter(
(groupId) => groupId !== item.groupId
);
this.setState({
collapsedState: newCollapsedIds,
});
}
};
// you can put this function inside
fetchAllData = () => {
fetch(
'https://otp.metroservices.io/otp/routers/default/index/routes/uscalacmtarail:801/stops'
)
.then((response) => response.json())
.then((productsList) => {
const newDataState = processWithGroups(
productsList,
this.state.dataState
);
this.setState({
products: productsList, // update the data
result: newDataState, // update the procesed data
});
});
};
// componentDidMount() {
// this.fetchAllData()
// }
render() {
const newData = setExpandedState({
data: this.state.result.data, // pass the proccessed data
collapsedIds: this.state.collapsedState,
});
return (
<div>
<FirstButton fetchData={this.fetchAllData}/>
<Grid
style={{
height: '520px',
}}
resizable={true}
reorderable={true}
filterable={true}
sortable={true}
groupable={true}
data={newData}
onDataStateChange={this.dataStateChange}
{...this.state.dataState}
onExpandChange={this.expandChange}
expandField="expanded"
>
<Column field="id" filterable={false} title="ID" width="50px" />
<Column field="name" title="Name" />
<Column field="cluster" title="Cluster" filter="numeric" />
</Grid>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('my-app'));
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>