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的改變并不會觸發(fā)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: '操作結(jié)果',
dataIndex: 'result',
key: 'result',
render(result) {
return result === "SUCCESS" ? "成功" : "失敗";
}
}]
return (
<div>
<Table
columns={columns}
rowKey={record => record.operatorTime}
dataSource={data}
pagination={pagination}
onChange={(pagination, filters, sorter) => this.handleChange(pagination, filters, sorter)}
/>
</div>
);
}
}
export default connect(
state => {
return {
filterLogs: state.audit.filterLogs
}
}
)(LogTable);
props屬性:
scopeType表示“用戶日志”或“管理員日志”
filterLogs表示過濾條件
state屬性:
data表示表格的數(shù)據(jù)源
pagination表示分頁信息
當props屬性的scopeType和filterLogs發(fā)生變化時涡拘,需要調(diào)用searchList從而更新data和pagination
然而,從上述代碼中發(fā)現(xiàn)模聋,當scopeType或filterLogs發(fā)生變化時,getDerivedStateFromProps和componentDidUpdate會分別執(zhí)行三次唠亚。第一次是由于props屬性的變化链方,而二、三次是由于在searchList中分別調(diào)用了兩次setState方法灶搜,那么setState為什么會觸發(fā)getDerivedStateFromProps呢祟蚀?
http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
查閱到上面的生命周期表后,發(fā)現(xiàn)割卖,^16.4以后前酿,set-State和forceUpdate也會觸發(fā)這個生命周期。因此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: '操作結(jié)果',
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 (
<Table
columns={columns}
rowKey={record => record.operatorTime}
dataSource={data}
pagination={pagination}
onChange={(pages) => handleChange(pages)}
/>
);
}
export default connect(
state => {
return {
filterLogs: state.audit.filterLogs
}
}
)(LogTable);
我不再需要去關(guān)心props屬性的變化狀態(tài)丙挽,不用去做各種判斷去控制是否渲染肺孵。就像vue里面的computed計算屬性,在react中使用useEffect颜阐,然后告訴它平窘,幫我盯著scopeType, filterLogs, current這三個變量,只要發(fā)生變化凳怨,就立刻計算瑰艘。
同時,我也不需要去寫N多this,就像阮大師說的:
React 團隊希望磅叛,組件不要變成復雜的容器屑咳,最好只是數(shù)據(jù)流的管道。開發(fā)者根據(jù)需要弊琴,組合管道即可兆龙。 組件的最佳寫法應(yīng)該是函數(shù),而不是類敲董。
代碼縮減了約50行紫皇,一氣呵成
驚艷!