Home > Software engineering >  Loading data into grid on click returns Uncaught (in promise) TypeError: Cannot read properties of u
Loading data into grid on click returns Uncaught (in promise) TypeError: Cannot read properties of u

Time:11-01

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>

  • Related