我发现这个datagrid反应组件?但我不确定他们是怎么写的?

时间:2018-06-12 04:49:23

标签: reactjs

有人可以解释一下代码是如何工作的吗?我理解反应,但我不清楚他们是如何将datagrid写成可重用的组件的?

我希望有一个数据网格,我可以用于与表相关的所有地方。并且,我发现下面的代码看起来很好,我想使用它。我知道反应js。感谢你的时间。

这是datagrid组件

import React, { Component } from "react";
import { Table, Button, Icon } from "semantic-ui-react";

import GridTopBar from "./GridTopBar";
import "./style.css";

const PAGE_SIZE = 10;

const BATCH_SIZE = 50;

const PAGE_MAX_INDEX = 5;

class Datagrid extends Component {
  state = { data: [] };

  page = {
    lastBatchIndex: 0,
    currentBatch: 0,
    currentPage: 0,
    batchData: []
  };

  actions = this.props.datasource.actions;

  pagination = this.props.datasource.pagination;

  componentWillMount() {
    this.loadData(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.loadData(nextProps);
  }

  loadData = iprops => {
    this.page.currentBatch = 1;
    this.page.currentPage = 1;

    const data = iprops.datasource.data;

    if (data == null) return;

    this.page.batchData = data;

    if (!iprops.datasource.pagination) {
      this.setState({ data });
      return;
    }

    let lastBatchIndex = Math.floor(this.pagination.totalRecords / BATCH_SIZE);
    lastBatchIndex += this.pagination.totalRecords % BATCH_SIZE > 0 ? 1 : 0;
    this.page.lastBatchIndex = lastBatchIndex;
    this.setState({ data: data.slice(0, PAGE_SIZE) });
  };

  fetchNextBatch = async () => {
    this.page.batchData = await this.actions.onFetchNextBatch(
      ++this.page.currentBatch
    );
    this.setState({ data: this.page.batchData.slice(0, PAGE_SIZE) });
  };

  fetchPreviousBatch = async () => {
    this.page.batchData = await this.actions.onFetchNextBatch(
      --this.page.currentBatch
    );
    this.setState({
      data: this.page.batchData.slice(BATCH_SIZE - PAGE_SIZE, BATCH_SIZE)
    });
  };

  onNext = async () => {
    if (this.page.currentPage === PAGE_MAX_INDEX) {
      this.page.currentPage = 1;
      await this.fetchNextBatch();
    } else {
      this.page.currentPage++;
      const startIdx = (this.page.currentPage - 1) * PAGE_SIZE;
      const endIdx = this.page.currentPage * PAGE_SIZE;
      this.setState({ data: this.page.batchData.slice(startIdx, endIdx) });
    }
  };

  onPrev = async () => {
    if (this.page.currentPage - 1 === 0) {
      this.page.currentPage = PAGE_MAX_INDEX;
      await this.fetchPreviousBatch();
    } else {
      this.page.currentPage--;
      const startIdx = (this.page.currentPage - 1) * PAGE_SIZE;
      const endIdx = this.page.currentPage * PAGE_SIZE;
      this.setState({ data: this.page.batchData.slice(startIdx, endIdx) });
    }
  };

  isFirstPage = () =>
    this.page.currentPage === 1 && this.page.currentBatch === 1;

  isLastPage = () => {
    if (this.page.batchData.length <= PAGE_SIZE) {
      return true;
    }

    if (this.page.lastBatchIndex !== this.page.currentBatch) {
      return false;
    }

    let lastPage = Math.floor(this.page.batchData.length / PAGE_SIZE);
    lastPage += this.page.batchData.length % PAGE_SIZE > 0 ? 1 : 0;

    if (lastPage === this.page.currentPage) {
      return true;
    }

    return false;
  };

  hasActions = () => Object.keys(this.actions).length > 0;

  // RENDERS
  renderRowActionButtons = val => {
    if (!this.hasActions()) {
      return null;
    }

    const renderEditButton = () => {
      if (!this.actions.onEdit) {
        return null;
      }

      return (
        <Button
          icon
          size="mini"
          compact
          onClick={() => this.actions.onEdit(val)}
        >
          <Icon name="write" />
        </Button>
      );
    };

    const renderDeleteButton = () => {
      if (!this.actions.onDelete) {
        return null;
      }

      return (
        <Button
          icon
          size="mini"
          color="blue"
          compact
          onClick={() => this.actions.onDelete(val)}
        >
          <Icon name="trash" />
        </Button>
      );
    };

    const renderSelectButton = () => {
      if (!this.actions.onSelect) {
        return null;
      }

      return (
        <Button
          id="grid-select-button"
          icon
          size="mini"
          color="orange"
          compact
          onClick={() => this.actions.onSelect(val)}
        >
          Select
        </Button>
      );
    };

    return (
      <Table.Cell>
        <Button.Group>
          {renderEditButton()}
          {renderDeleteButton()}
          {renderSelectButton()}
        </Button.Group>
      </Table.Cell>
    );
  };

  renderRowData = val =>
    Object.keys(val)
      .filter(k => this.props.datasource.filter(k))
      .map(key => <Table.Cell key={key}>{val[key]}</Table.Cell>);

  renderHeaderRow = () => {
    const headers = this.props.datasource.headers.map(col => (
      <Table.HeaderCell key={col}>{col}</Table.HeaderCell>
    ));
    if (this.hasActions()) {
      headers.push(<Table.HeaderCell key="Actions">Actions</Table.HeaderCell>);
    }
    return headers;
  };

  renderPagination = () => {
    if (!this.pagination) return null;

    const { showPagination } = this.pagination;

    if (!showPagination) return null;

    return (
      <div
        style={{
          float: "right",
          border: "1px lightgrey solid",
          borderRadius: 5
        }}
      >
        <Button.Group>
          <Button
            onClick={this.onPrev}
            disabled={this.isFirstPage()}
            content="<< Prev"
            basic
            style={{ borderRight: "1px lightgrey solid" }}
          />
          <Button
            content="Next >>"
            basic
            onClick={this.onNext}
            disabled={this.isLastPage()}
          />
        </Button.Group>
      </div>
    );
  };

  renderRows = () =>
    this.state.data.map(val => (
      <Table.Row key={val.id}>
        {this.renderRowData(val)}
        {this.renderRowActionButtons(val)}
      </Table.Row>
    ));

  renderTable = () => {
    if (this.props.datasource.data == null) {
      return null;
    }

    return (
      <div>
        <Table celled compact className="gridview">
          <Table.Header>
            <Table.Row>{this.renderHeaderRow()}</Table.Row>
          </Table.Header>
          <Table.Body>{this.renderRows()}</Table.Body>
        </Table>
        {this.renderPagination()}
      </div>
    );
  };

  // Main render.
  render() {
    const { actions } = this.props.datasource;

    return (
      <div>
        <GridTopBar
          searchText={`${this.props.datasource.headers[0]}..`}
          onSearch={actions.onSearch}
          onCreateNew={actions.onCreateNew}
          onFetchAll={actions.onFetchAll}
        />
        {this.renderTable()}
      </div>
    );
  }
}

export default Datagrid;

这是客户组件。

import React, { Component } from "react";
import { Titlebar, Datagrid, Loader, MessageBox, YesNo } from "../controls";
import AddOrUpdateCustomer from "./AddOrUpdateCustomer";
import api from "../../api";

class Customers extends Component {
  currentCustomer = {};

  customerDefault = {
    id: "",
    name: "",
    description: "",
    address: ""
  };

  gridSource = {
    headers: ["Customer Id", "Name", "Details", "Adress"],
    filter: key =>
      key !== "created_at" && key !== "updated_at" && key !== "user_id",
    actions: {
      onEdit: id => this.onEdit(id),
      onDelete: id => this.onDelete(id),
      onCreateNew: () => this.onCreateNew(),
      onFetchAll: () => this.onFetchAll(),
      onSearch: query => this.onSearch(query),
      onFetchNextBatch: idx => this.onFetchNextBatch(idx)
    },
    data: null,
    pagination: {
      showPagination: true,
      totalRecords: 0
    }
  };

  state = {
    isLoading: false,
    canShowAddOrUpdate: false,
    canShowError: false,
    canShowConfirmDelete: false,
    errorMessage: "",
    isEdit: false,
    customer: this.customerDefault,
    datasource: this.gridSource
  };

  async componentWillMount() {
    this.onFetchAll();
  }

  setDataSource = (customers, count) => {
    const { datasource } = this.state;
    datasource.data = customers;
    datasource.pagination.totalRecords = count;
    this.setState({ datasource, isLoading: false });
  };

  onFetchNextBatch = async idx => {
    const customers = await api.customers.getPage(idx);
    return customers;
  };

  onFetchAll = async () => {
    this.setState({ isLoading: true });
    const res = await api.customers.count();
    const customers = await api.customers.getPage(1);
    this.setDataSource(customers, res[0].count);
  };

  onSearch = async query => {
    const res = await api.customers.count(query);
    const customers = await api.customers.search(query);
    this.setDataSource(customers, res[0].count);
  };

  onCreateNew = () => {
    this.setState({
      canShowAddOrUpdate: true,
      isEdit: false,
      customer: this.customerDefault
    });
  };

  onEdit = customer => {
    this.currentCustomer.id = customer.id;
    this.setState({ canShowAddOrUpdate: true, isEdit: true, customer });
  };

  onDelete = customer => {
    this.currentCustomer = customer;
    this.setState({ canShowConfirmDelete: true });
  };

  deleteCustomer = async () => {
    try {
      this.setState({ canShowConfirmDelete: false, isLoading: false });
      await api.customers.delete(this.currentCustomer.id);
      this.showMessageBox("Deleted successfully.");
    } catch (error) {
      this.showMessageBox(error.message);
    } finally {
      await this.onFetchAll();
      this.setState({ isLoading: false });
    }
  };

  onSubmitForm = async data => {
    try {
      this.setState({ customer: data, isLoading: true });

      let res = "";
      let message = "";

      if (this.state.isEdit)
        res = await api.customers.update(this.currentCustomer.id, data);
      else res = await api.customers.createNew(data);

      console.log(res);

      if (res.data.status === "FAILED") {
        message =
          res.data.message.length === 0
            ? "Something went wrong. Please try again"
            : res.data.message;
      } else {
        message =
          res.data.message.length === 0
            ? "Saved successfully."
            : res.data.message;
      }

      this.showMessageBox(message);
    } catch (error) {
      this.showMessageBox(error.message);
    } finally {
      await this.onFetchAll();
      this.onAddOrUpdateDialogClose();
    }
  };

  showMessageBox = message => {
    this.setState({
      errorMessage: message,
      canShowError: true
    });
  };

  onAddOrUpdateDialogClose = () => {
    this.setState({
      canShowAddOrUpdate: false,
      isEdit: false,
      customer: this.customerDefault,
      isLoading: false
    });
  };

  render() {
    return (
      <div>
        <Titlebar title="Customers" />
        <Loader isLoading={this.state.isLoading} />
        <Datagrid datasource={this.state.datasource} />
        <AddOrUpdateCustomer
          isEdit={this.state.isEdit}
          data={this.state.customer}
          canShowDialog={this.state.canShowAddOrUpdate}
          onDialogClose={this.onAddOrUpdateDialogClose}
          onSubmit={this.onSubmitForm}
          headerText="Create product type"
        />
        <MessageBox
          message={this.state.errorMessage}
          open={this.state.canShowError}
          onClose={() => this.setState({ canShowError: false })}
        />
        {this.state.canShowConfirmDelete ? (
          <YesNo
            message="Are you sure want to delete the selected expense type?"
            onNo={() => this.setState({ canShowConfirmDelete: false })}
            onYes={this.deleteCustomer}
          />
        ) : null}
      </div>
    );
  }
}

export default Customers;

0 个答案:

没有答案