我对React还是比较陌生的,在这个React组件中,我必须缺少一些基本知识。非常感谢您提供有关该解决方案的指导。
我要在此处实现的功能-使用后端的mongoose-paginate和前端的Material-UI TablePagination 实现分页结束。因此,每次用户单击下一页图标(向前或向后箭头)时,都会使用axios.get进行数据库调用,并且将从mongo中获取数据并将其呈现在UI的表格中。
要实现这一点,我在React中有handleChangePage()函数,它将调用axios.get函数。
问题-从第二页开始,数据没有重新发布,但是通过console.log,我可以看到(在chrome-devtool中)单击后确实从后端获取了数据下一页图标。但是,获取的数据不会在UI中呈现。
这是我的渲染组件中的React代码。关键功能是 handleChangePage(),这是我每次都要执行数据库调用以获取数据的位置,用户单击下一页图标(下一页图标是Material-UI的 TablePagination 组件)
class List extends Component {
constructor(props) {
super(props);
this.state = {
allDevelopmentWorks: [],
allDevelopmentWorksFormatted: [],
selected: [],
page: 0,
rowsPerPage: 5,
renderOnlyDateRangeData: false,
developmentWorksDateRange: []
};
}
// Function to handle the the request from user to sort by a particular heading.
handleRequestSort = (event, property) => {
const orderBy = property;
let order = "desc";
if (this.state.orderBy === property && this.state.order === "desc") {
order = "asc";
}
this.setState({ order, orderBy });
};
handleSelectAllClick = event => {
if (event.target.checked) {
this.setState(state => ({
selected: state.allDevelopmentWorks.map(n => n._id)
}));
return;
}
this.setState({ selected: [] });
};
handleClick = (event, id) => {
const { selected } = this.state;
const selectedIndex = selected.indexOf(id);
let newSelected = [];
if (selectedIndex === -1) {
newSelected = newSelected.concat(selected, id);
} else if (selectedIndex === 0) {
newSelected = newSelected.concat(selected.slice(1));
} else if (selectedIndex === selected.length - 1) {
newSelected = newSelected.concat(selected.slice(0, -1));
} else if (selectedIndex > 0) {
newSelected = newSelected.concat(
selected.slice(0, selectedIndex),
selected.slice(selectedIndex + 1)
);
}
this.setState({ selected: newSelected });
};
componentDidMount() {
axios
.get("/api/developmenties/")
.then(res => {
this.setState(
{
allDevelopmentWorksFormatted: res.data
},
() => {
this.state.allDevelopmentWorksFormatted.map((item, index) => {
if (item.date_of_commencement || item.date_of_completion) {
this.state.allDevelopmentWorksFormatted[
index
].date_of_commencement =
moment(item.date_of_commencement).format(
"MMM D, YYYY 12:00:00 "
) + `AM`;
this.state.allDevelopmentWorksFormatted[
index
].date_of_completion =
moment(item.date_of_completion).format(
"MMM D, YYYY 12:00:00 "
) + `AM`;
}
});
}
);
})
.then(
axios
.get("/api/developmenties/paginate", {
params: {
page: this.state.page,
rowsperpage: this.state.rowsPerPage
}
})
.then(res => {
console.log("THE RESPONSE FOR PAGINATION IS ", res.data);
this.setState({
allDevelopmentWorks: res.data
});
})
)
.catch(function(error) {
console.log(error);
});
}
componentDidUpdate(prevProps, prevState) {
if (
this.state.developmentWorksDateRange.length !==
prevState.developmentWorksDateRange.length ||
this.state.allDevelopmentWorksFormatted.length !==
prevState.allDevelopmentWorksFormatted.length ||
this.state.rowsPerPage !== prevState.rowsPerPage
) {
return axios
.get("/api/developmenties/paginate", {
params: {
page: this.state.page,
rowsperpage: this.state.rowsPerPage
}
})
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
})
.catch(function(error) {
console.log(error);
});
}
}
handleChangePage = async (event, page) => {
// console.log("THIS PAGE NO IS ", page);
await this.setState({ page });
const res = await axios.get(`/api/developmenties/paginate`, {
params: {
page: page,
rowsperpage: this.state.rowsPerPage
}
});
this.setState({
allDevelopmentWorks: res.data
});
};
handleChangeRowsPerPage = event => {
this.setState({ rowsPerPage: event.target.value });
};
isSelected = id => this.state.selected.indexOf(id) !== -1;
unSelectItems = () => {
this.setState({
selected: []
});
};
handleQueryString = queryTypedInChild => {
this.setState({
queryStringFromChild: queryTypedInChild
});
};
handleColumnToQuery = columnToQueryInChild => {
this.setState({
columnToQuery: columnToQueryInChild
});
};
clearAllQueryString = () => {
this.setState({
queryStringFromChild: "",
columnToQuery: "location"
});
};
ifUserWantsDateRangeData = dateRangeArr => {
this.setState({
developmentWorksDateRange: [...dateRangeArr]
});
};
render() {
const { classes } = this.props;
const {
order,
orderBy,
selected,
rowsPerPage,
page,
allDevelopmentWorks,
developmentWorksDateRange,
allDevelopmentWorksFormatted,
queryStringFromChild
} = this.state;
const emptyRows =
rowsPerPage -
Math.min(rowsPerPage, allDevelopmentWorks.length - page * rowsPerPage);
// in below the whole table header is a different component 'EnhancedTableHead'
return (
<MuiThemeProvider>
<div>
<Row>
<Col xs="12">
{console.log(
"CURRENT DEVELOPMENT LIST RENDERED IS ",
allDevelopmentWorks
)}
<Paper className={classes.root}>
<Table className={classes.table}>
<TableBody>
{stableSort(
allDevelopmentWorks,
getSorting(order, orderBy)
)
.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
)
.map(n => {
const isSelected = this.isSelected(n._id);
return (
<TableRow
hover
onClick={event => this.handleClick(event, n._id)}
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n._id}
selected={isSelected}
>
<CustomTableCell padding="checkbox">
<Checkbox checked={isSelected} />
</CustomTableCell>
<CustomTableCell
component="th"
scope="row"
padding="none"
>
{n.location}
</CustomTableCell>
<CustomTableCell align="right">
{n.work_description}
</CustomTableCell>
<CustomTableCell align="right">
{moment(n.date_of_commencement).format(
"MMM D, YYYY 12:00:00 "
)}{" "}
{`AM`}
</CustomTableCell>
<CustomTableCell align="right">
{moment(n.date_of_completion).format(
"MMM D, YYYY 12:00:00 "
)}{" "}
{`AM`}
</CustomTableCell>
<CustomTableCell align="right">
{n.status_of_work}
</CustomTableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<CustomTableCell colSpan={6} />
</TableRow>
)}
</TableBody>
</Table>
<TablePagination
rowsPerPageOptions={[5, 10, 25]}
component="div"
count={allDevelopmentWorksFormatted.length}
rowsPerPage={rowsPerPage}
page={page}
backIconButtonProps={{
"aria-label": "Previous Page"
}}
nextIconButtonProps={{
"aria-label": "Next Page"
}}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
/>
</Paper>
</Col>
</Row>
<Row>
<br />
</Row>
</div>
</MuiThemeProvider>
);
}
}
List.propTypes = {
classes: PropTypes.object.isRequired
};
export default withStyles(styles)(List);
据我所知,问题的根源是在其中处理两个setState的 handleChangePage()函数。第一个setstate this.setState({page})正在触发重新渲染,并使列表仅使用当前数据重新渲染(即,在此函数中的下一个axios.get请求被触发之前)并更新变量 allDevelopmentWorks )
handleChangePage = async (event, page) => {
await this.setState({ page });
await axios
.get(`/api/developmenties/paginate`, {
params: {
page: this.state.page,
rowsperpage: this.state.rowsPerPage
}
})
.then(res => {
this.setState({
allDevelopmentWorks: res.data
});
console.log(
"AFTER SETSTATE UPDATED ALL-DEVELOPMENTWORKS IS ",
this.state.allDevelopmentWorks
);
})
.catch(function(error) {
console.log(error);
});
};
因此,我尝试仅在使用以下代码的this.setState({ page })
之后停止重新渲染组件,但未解决我的问题
shouldComponentUpdate(nextProps, nextState) {
if (this.state.page !== nextState.page) {
return false;
}
return true;
}
以下是我在Express中用于从mongo数据库获取数据的后端路由代码。开发是我的猫鼬模式的名字。
// To GET ALL DevelopmentWorks - max 5 or 10 or 15 at a time (determined by whatever users sets it to be at the front-end MAT-UI)
router.get("/paginate", (req, res, next) => {
console.log("THE REQ.QUERY FOR PAGINATION IS ", req.query);
let pageOptions = {
page: parseInt(req.query.page) || 0,
limit: parseInt(req.query.rowsperpage) || 5
};
if (req.query.page && req.query.rowsperpage) {
Development.paginate(
{},
{
offset: pageOptions.page * pageOptions.limit,
limit: pageOptions.limit
},
(err, result) => {
if (err) {
console.log(err);
next(err);
} else {
res.status(200).json(result.docs);
}
}
);
}
});
// To GET ALL DevelopmentWorks
router.route("/").get((req, res, next) => {
Development.find(
{},
null,
{
sort: { createdAt: -1 }
},
(err, docs) => {
// Development.find({ port: req.body.port._id }, (err, docs) => {
if (err) {
return next(err);
} else {
res.status(200).json(docs);
}
}
);
});
更多说明-当我不使用 mongoose-paginate 并加载整个数据(通过单次调用将其获取到数据库)时, TablePaginaton 就可以了正确地。但是现在要实现分页,我希望每次用户单击下一页图标时都进行新的服务器调用。
答案 0 :(得分:1)
在解决问题后,回答我自己的问题。问题是我将数据切片两次以在表中呈现。因此,在整合了mongoose-paginate的情况下,切片工作是由后端本身完成的,因为mongoose-paginate只会将切片的数据发送到前端。但是我的错误是,在渲染表期间,我再次进行切片(这是在整合mongoosse-paginate之前一次获取全部数据时所需的)。这是上面代码的更正部分(即,我将表放到return()内的地方)。
<TableBody>
{stableSort(
allDevelopmentWorks,
getSorting(order, orderBy)
)
.map(n => {
const isSelected = this.isSelected(n._id);
return (
<TableRow
hover
onClick={event => this.handleClick(event, n._id)}
role="checkbox"
aria-checked={isSelected}
tabIndex={-1}
key={n._id}
selected={isSelected}
>
<CustomTableCell padding="checkbox">
<Checkbox checked={isSelected} />
</CustomTableCell>
<CustomTableCell
component="th"
scope="row"
padding="none"
>
{n.location}
</CustomTableCell>
<CustomTableCell align="right">
{n.work_description}
</CustomTableCell>
<CustomTableCell align="right">
{moment(n.date_of_commencement).format(
"MMM D, YYYY 12:00:00 "
)}{" "}
{`AM`}
</CustomTableCell>
<CustomTableCell align="right">
{moment(n.date_of_completion).format(
"MMM D, YYYY 12:00:00 "
)}{" "}
{`AM`}
</CustomTableCell>
<CustomTableCell align="right">
{n.status_of_work}
</CustomTableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 49 * emptyRows }}>
<CustomTableCell colSpan={6} />
</TableRow>
)}
</TableBody>
我只需要删除零件
.slice(
page * rowsPerPage,
page * rowsPerPage + rowsPerPage
)