getDerivedStateFromProps +componentDidUpdate 使用方法:
import React from 'react';
import { connect } from 'react-redux';
import { Card, Table, Divider, Modal } from 'antd';
import util from 'scripts/utils/util';
import { operateType } from 'scripts/app/message';
import service from 'scripts/services/auditService';
import sty from '../audit.scss';
class LogTable extends React.Component {
state = {
data: [],
scopeType: this.props.scopeType, //常见错误,props上scopeType的改变并不会触发state中scopeType的改变
pagination: {
current: 1,
pageSize: 10
},
filterLogs: this.props.filterLogs,
}
componentDidMount() {
this.searchList();
}
static getDerivedStateFromProps(props, state) {
let data = {}
if (state.scopeType !== props.scopeType) {
data["scopeType"] = props.scopeType
}
if (JSON.stringify(state.filterLogs) !== JSON.stringify(props.filterLogs)) { //Todo 判断对象是否改变
data["filterLogs"] = {
...props.filterLogs
}
}
return data;
}
componentDidUpdate(prevProps, prevState) {
if (prevState.scopeType !== this.state.scopeType) {
this.searchList();
}
if (JSON.stringify(prevProps.filterLogs) !== JSON.stringify(this.props.filterLogs)) { //Todo 判断对象是否改变
this.searchList();
}
}
searchList(current) {
if (!this.state.filterLogs) return;
const { filterLogs } = this.props;
const { scopeType, pagination } = this.state;
filterLogs.filterMap.scope = scopeType;
let filters = {
...filterLogs,
...pagination,
current: current || 1
};
service.searchLoglist(filters).then(res => {
if (res.success) {
this.setState({ data: res.data });
}
});
service.loadLoglist(filters).then(res => {
if (res.success) {
this.setState({
pagination: {
...this.state.pagination,
current: current || 1,
total: res.data
}
})
}
});
}
handleChange(pagination) {
this.setState({
pagination: {
...this.state.pagination,
current: pagination.current
}
})
this.searchList(pagination.current);
}
render() {
const { data, scopeType, pagination } = this.state;
const columns = [{
title: '序号',
key: 'id',
render(data, record, index) {
return (pagination.current - 1) * 10 + index + 1;
}
}, {
title: '操作时间',
dataIndex: 'operatorTime',
key: 'operatorTime',
render(operatorTime) {
return new Date(operatorTime).format('yyyy-mmon-dd hh:mm');
}
}, {
title: "客户端IP",
dataIndex: 'ip',
key: 'ip'
}, {
title: '用户昵称',
dataIndex: 'operatorNickName',
key: 'operatorNickName'
}, {
title: '用户邮箱',
dataIndex: 'operatorEmail',
key: 'operatorEmail',
render(operatorEmail) {
return operatorEmail == 'null' ? '' : operatorEmail;
}
}, {
title: '操作类型',
key: 'operateType',
render(record) {
return operateType[record.operateType];
}
}, {
title: '操作对象',
dataIndex: 'targetName',
key: 'targetName',
render(targetName) {
return util.msgType(targetName);
}
}, {
title: '操作结果',
dataIndex: 'result',
key: 'result',
render(result) {
return result === "SUCCESS" ? "成功" : "失败";
}
}]
return (
record.operatorTime}
dataSource={data}
pagination={pagination}
onChange={(pagination, filters, sorter) => this.handleChange(pagination, filters, sorter)}
/>
);
}
}
export default connect(
state => {
return {
filterLogs: state.audit.filterLogs
}
}
)(LogTable);
props属性:
scopeType表示“用户日志”或“管理员日志”
filterLogs表示过滤条件
state属性:
data表示表格的数据源
pagination表示分页信息
当props属性的scopeType和filterLogs发生变化时,需要调用searchList从而更新data和pagination
然而,从上述代码中发现,当scopeType或filterLogs发生变化时,getDerivedStateFromProps和componentDidUpdate会分别执行三次。第一次是由于props属性的变化,而二、三次是由于在searchList中分别调用了两次setState方法,那么setState为什么会触发getDerivedStateFromProps呢?
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
查阅到上面的生命周期表后,发现,^16.4以后,setState和forceUpdate也会触发这个生命周期。因此state变化后,又会走 getDerivedStateFromProps 方法,并把 state 值更新为传入的 prop。
react Hooks使用方法:
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { Table } from 'antd';
import util from 'scripts/utils/util';
import { operateType } from 'scripts/app/message';
import service from 'scripts/services/AuditService';
function LogTable({ scopeType, filterLogs }) {
const [data, setData] = useState([]);
const [pagination, setPagination] = useState({ pageSize: 10 });
const [current, setCurrent] = useState(1);
const columns = [{
title: '序号',
key: 'id',
render(data, record, index) {
return (pagination.current - 1) * 10 + index + 1;
}
}, {
title: '操作时间',
dataIndex: 'operatorTime',
key: 'operatorTime',
render(operatorTime) {
return new Date(operatorTime).format('yyyy-mmon-dd hh:mm');
}
}, {
title: "客户端IP",
dataIndex: 'ip',
key: 'ip'
}, {
title: '用户昵称',
dataIndex: 'operatorNickName',
key: 'operatorNickName'
}, {
title: '用户邮箱',
dataIndex: 'operatorEmail',
key: 'operatorEmail',
render(operatorEmail) {
return operatorEmail == 'null' ? '' : operatorEmail;
}
}, {
title: '操作类型',
key: 'operateType',
render(record) {
return operateType[record.operateType];
}
}, {
title: '操作对象',
dataIndex: 'targetName',
key: 'targetName',
render(targetName) {
return util.msgType(targetName);
}
}, {
title: '操作结果',
dataIndex: 'result',
key: 'result',
render(result) {
return result === "SUCCESS" ? "成功" : "失败";
}
}];
useEffect(() => {
if (!filterLogs) return;
filterLogs.filterMap.scope = scopeType;
let filters = {
...filterLogs,
...pagination,
current: current || 1
};
service.searchLoglist(filters).then(res => {
if (res.success) {
setData(res.data);
}
});
service.loadLoglist(filters).then(res => {
if (res.success) {
setPagination({
...pagination,
current: current || 1,
total: res.data
});
}
});
}, [scopeType, filterLogs, current])
function handleChange(pageInfo) {
setCurrent(pageInfo.current)
}
return (
record.operatorTime}
dataSource={data}
pagination={pagination}
onChange={(pages) => handleChange(pages)}
/>
);
}
export default connect(
state => {
return {
filterLogs: state.audit.filterLogs
}
}
)(LogTable);
我不再需要去关心props属性的变化状态,不用去做各种判断去控制是否渲染。就像vue里面的computed计算属性,在react中使用useEffect,然后告诉它,帮我盯着scopeType, filterLogs, current这三个变量,只要发生变化,就立刻计算。
同时,我也不需要去写N多this,就像阮大师说的:
React 团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。 组件的最佳写法应该是函数,而不是类。
代码缩减了约50行,一气呵成
惊艳!