0

The question comes from a issue where I need data binding and save it to a reducer so I can use pusher to modify the data when needed and it changes in real-time. The problems I find are that:

  1. I am new in react and I don't really know much about how to bind data variables.

  2. I am using remote data with fetch so the data can be refreshed but it can't seem to find a way to properly bind or even save it to a reducer.

Below, the relevant code:

class MainTable extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
      <MaterialTable
        tableRef={this.tableRef}
        columns={columnsSetup}
        options={materialTableOptions}
        data={query =>
          new Promise((resolve, reject) => {
            pageQuery = query.page;
            pageSizeQuery = query.pageSize;
            let url = GET_ORDERS_URL;
            url += 'qtt=' + pageSizeQuery;
            url += '&page=' + pageQuery;

            fetch(url)
              .then(response => response.json())
              .then(result => {
                resolve({
                  data: result.data,
                  page: result.page,
                  totalCount: result.totalElems
                });
              });
          })
        }
      />
    );
  }
}
Jurrian
  • 850
  • 6
  • 20
BryceSoker
  • 624
  • 1
  • 11
  • 29

2 Answers2

2

Data fetching should be done in one of the react lifecycle methods. These are build-in functions that will be called on specific "life" events of your component, for example when it gets mounted (componentDidMount).

You should read the docs thoroughly to really get the hang of it.

To give you an example of the implementation of a lifecycle method, I fixed your code below.

A couple of important, but also opinionated, subjects to look into are: lifecycle methods, state, Async/await (instead of promises), Components: classes and hooks.

class MainTable extends React.Component {
  state = {
    data: {}
  };

  componentDidMount() {
    this.fetchData();
  }

  fetchData = async query => {
    let url = `${GET_ORDERS_URL}qtt=${query.pageSize}&page=${query.page}`;

    const response = await fetch(url);
    const result = response.json();

    this.setState({
      data: {
        data: result.data,
        page: result.page,
        totalCount: result.totalElems
      }
    });
  };

  render() {
    return (
      <MaterialTable
        tableRef={this.tableRef}
        columns={columnsSetup}
        options={materialTableOptions}
        data={this.state.data}
      />
    );
  }
}

Below is a functional component (exactly the same logic as above) that uses hooks:

import React, { useEffect, useState } from 'react';

function MainTable() {
  const [data, setData] = useState({});

  useEffect(() => {
    const fetchData = async query => {
      let url = `${GET_ORDERS_URL}qtt=${query.pageSize}&page=${query.page}`;

      const response = await fetch(url);
      const result = response.json();

      setData({
        data: result.data,
        page: result.page,
        totalCount: result.totalElems
      });
    };
    fetchData();
  }, [data]);

  return (
    <MaterialTable
      columns={columnsSetup}
      options={materialTableOptions}
      data={data}
    />
  );
}
Jurrian
  • 850
  • 6
  • 20
  • I had a few classes on reactJS and the lifecycle through class is what I normally use, however this Material-table seems to have some issues with it. Using the code above I get 2 errors, the first one is a "TypeError: _this.props.data is not a function" on the library material-table.js. The second one is on the line url of this file, where he can't find pageSize because query is undefined, as in it's probably not linked to the Material Table. – BryceSoker Dec 06 '19 at 16:11
  • The example that uses hooks won't work. You cannot use "this" if you are not using class. Needs to be – Adrián Rodriguez Sep 08 '20 at 07:23
  • 1
    @AdriánRodriguez You're right. I didn't test it myself, just wanted to give a simple example. – Jurrian Sep 08 '20 at 11:50
0

Material-table is a fantastic out the box soloution for tables however, I don't particularity like the way the pagination is handled. I use await and async operators rather than promises and wanted my component to be responsible for managing the state rather than these promise methods that material-table wants you to provide. Material-table provide a way to completely override their pagination logic so this is what I did.

material-table's Pagination component appears to just be a wrapper Material UI's TablePagination component.

const [data,setData] = React.useState([])
const [pagination, setPagination] = React.useState({take: 20, page: 0})
const [count, setCount] = React.useState(0)

React.useEffect(() => {
  async function fetch() {
      var {result, count} = await someAsyncCallToServer()
      setData(fetch)
      setCount(count)        
    }
    fetch()
  }
  ,[pagination])

const handleChangePage = (event, newPage) => {
    setPagination(old => ({...old, page: newPage}))
  }


...
<MaterialTable
  data={data}
  ...
  components = {{
     Pagination : props => 
       <TablePagination
         rowsPerPage={pagination.take}
         onChangeRowsPerPage={take => setPagination(old=> ({...old, take}))}
         page={pagination.page}
         count={count}
         onChangePage={handleChangePage}
        />
  }}
/>
Max Carroll
  • 4,441
  • 2
  • 31
  • 31