实战升级react hooks

2019-11-20  本文已影响0人  web_柚子小记

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 (
            <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);
image.png

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以后,set­State和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 (
        <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);

我不再需要去关心props属性的变化状态,不用去做各种判断去控制是否渲染。就像vue里面的computed计算属性,在react中使用useEffect,然后告诉它,帮我盯着scopeType, filterLogs, current这三个变量,只要发生变化,就立刻计算。
同时,我也不需要去写N多this,就像阮大师说的:
React 团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。 组件的最佳写法应该是函数,而不是类。

代码缩减了约50行,一气呵成
惊艳!

上一篇下一篇

猜你喜欢

热点阅读