有人可以解释一下代码是如何工作的吗?我理解反应,但我不清楚他们是如何将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;