Javascript 什么';使用React实现可排序表的正确方法是什么?

Javascript 什么';使用React实现可排序表的正确方法是什么?,javascript,reactjs,Javascript,Reactjs,我目前的执行情况: export const SORT_ORDER = { ASC: "ascending", DESC: "descending", OTHER: "other" }; export default class Table extends React.Component { constructor(props) { super(props); this.sortIcon = new Map();

我目前的执行情况:

export const SORT_ORDER = {
    ASC: "ascending",
    DESC: "descending",
    OTHER: "other"
};

export default class Table extends React.Component {

    constructor(props) {
        super(props);

        this.sortIcon = new Map();
        this.sortIcon.set(SORT_ORDER.ASC, sortAsc);
        this.sortIcon.set(SORT_ORDER.DESC, sortDesc);
        this.sortIcon.set(SORT_ORDER.OTHER, sortOther);

        this.state = {
            sortField: this.props.defaultSortColumn,
            sortOrder: this.props.defaultSortOrder
        };
    }

    componentDidMount() {
        this.sort(this.props.defaultSortColumn, this.props.defaultSortOrder)();
    }

    retrieveOrder = (columnId) => {
        return columnId === this.state.sortField ? this.state.sortOrder : SORT_ORDER.OTHER;
    };

    nextOrder = (current) => {
        if (current === SORT_ORDER.DESC) {
            return SORT_ORDER.ASC;
        } else if (current === SORT_ORDER.ASC) {
            return SORT_ORDER.DESC;
        } else {
            return this.props.defaultSortOrder;
        }
    };

    sort = (columnId, order) => () => {
        let descriptor = this.props.structure[columnId];
        let values = this.props.value.slice();

        let orderFactor = order === SORT_ORDER.ASC ? 1 : -1;
        values.sort((a, b) => {
            let first = descriptor.render(a);
            let second = descriptor.render(b);
            return first > second ? orderFactor : first < second ? -orderFactor : 0;
        });

        this.setState({
            sortField: columnId,
            sortOrder: order
        });
        this.props.onSort(values);
    };

    renderHeader = (id, descriptor) => {
        let order = this.retrieveOrder(id);
        let iconSrc = this.sortIcon.get(order);
        let nextOrder = this.nextOrder(this.retrieveOrder(id));
        return (
            <th key={id} className={descriptor.headStyle}>
                <a href="#" aria-sort={order} onClick={this.sort(id, nextOrder)}>
                    <img src={iconSrc}/>
                    {descriptor.label}
                </a>
            </th>
        );
    };

    render()  {
        return (
            <table>
                Table structure
            </table>
        );
    }
}
导出常量排序\u顺序={
ASC:“上升”,
描述:“下降”,
其他:“其他”
};
导出默认类表扩展React.Component{
建造师(道具){
超级(道具);
this.sortIcon=新地图();
this.sortIcon.set(SORT\u ORDER.ASC,sortAsc);
this.sortIcon.set(SORT_ORDER.DESC,sortDesc);
this.sortIcon.set(排序顺序、其他、排序);
此.state={
sortField:this.props.defaultSortColumn,
sortOrder:this.props.defaultSortOrder
};
}
componentDidMount(){
this.sort(this.props.defaultSortColumn,this.props.defaultSortOrder)();
}
检索顺序=(列ID)=>{
return columnId===this.state.sortField?this.state.sortOrder:SORT\u ORDER.OTHER;
};
nextOrder=(当前)=>{
如果(当前===排序顺序.DESC){
返回SORT_ORDER.ASC;
}else if(当前===SORT\u ORDER.ASC){
返回SORT_ORDER.DESC;
}否则{
返回此.props.defaultSortOrder;
}
};
排序=(列ID,顺序)=>()=>{
让descriptor=this.props.structure[columnId];
让values=this.props.value.slice();
让orderFactor=order==SORT\u order.ASC?1:-1;
值。排序((a,b)=>{
设first=descriptor.render(a);
设second=descriptor.render(b);
返回第一个>第二个?orderFactor:first{
let order=this.retrieveOrder(id);
让iconrc=this.sortIcon.get(order);
设nextOrder=this.nextOrder(this.retrieveOrder(id));
返回(
);
};
render(){
返回(
表结构
);
}
}
父组件以下一种方式声明它:

<Table structure={this.tableHeader} value={this.state.tableValue} onSort={this.handleChange('tableValue')}
     defaultSortColumn="created" defaultSortOrder={SORT_ORDER.DESC} />

表值在props中定义为
value
onSort
是一个更改父组件状态的函数=>它更改表值。此外,我还有
defaultSortColumn
defaultSortOrder
来在表格填充后对其进行排序

问题是我的表可以在页面上声明多次

所以

1) 我无法将表值存储在其状态。我应该吗

2) 如何在不使用
componentDidMount
的情况下实现默认排序?使用当前实现时,当调用
componentDidMount
时,默认排序只发生一次,但我在页面上有多个
组件。 我尝试使用
组件willreceiveprops
函数,但在
排序
函数中更改
状态时也会调用该函数。所以我不能使用它。

我的最终解决方案是:

export const SORT_ORDER = {
    ASC: "ascending",
    DESC: "descending",
    OTHER: "other"
};

class TableRow extends React.Component {

    render() {
        return (
            <tr>
                {this.props.children}
            </tr>
        );
    }
}


class TableHeader extends React.Component {

    constructor(props) {
        super(props);

        this.sortIcon = new Map([
            [SORT_ORDER.ASC, {icon: sortAsc, title: "Ascending"}],
            [SORT_ORDER.DESC, {icon: sortDesc, title: "Descending"}],
            [SORT_ORDER.OTHER, {icon: sortOther, title: "Unsorted"}]
        ]);
    }

    render() {
        const {children, onClick, sortOrder} = this.props;
        return (
            <th>
               {onClick ? (
                <a href="#" aria-sort={sortOrder} onClick={onClick}>
                    <img src={this.sortIcon.get(sortOrder).icon} title={this.sortIcon.get(sortOrder).title} />
                    {children}
                </a>
            ) : children}
            </th>
        );
    }
}

export default class Table extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            sortField: props.defaultSortColumn,
            sortOrder: props.defaultSortOrder
        };
    }

    retrieveOrder = (columnId) => {
        return columnId === this.state.sortField ? this.state.sortOrder : SORT_ORDER.OTHER;
    };

    nextOrder = (current) => {
        if (current === SORT_ORDER.DESC) {
            return SORT_ORDER.ASC;
        } else if (current === SORT_ORDER.ASC) {
            return SORT_ORDER.DESC;
        } else {
            return this.props.defaultSortOrder;
        }
    };

    sortedRows = () => {
        let descriptor = this.props.structure.find(d => d.attribute === this.state.sortField);
        let values = this.props.value.slice();

        let orderFactor = this.state.sortOrder === SORT_ORDER.ASC ? 1 : -1;
        return values.sort((a, b) => {
            let first;
            let second;
            // null and undefined values should be changed to empty string
            if (typeof a[descriptor.attribute] === "number" || typeof b[descriptor.attribute] === "number") {
                first = a[descriptor.attribute] || "";
                second = b[descriptor.attribute] || "";
            } else {
                first = descriptor.render(a) || "";
                second = descriptor.render(b) || "";
            }
            return first > second ? orderFactor : first < second ? -orderFactor : 0;
        });
    };

    renderHeaders = () => {
        return this.props.structure.map((descriptor, id) => {
            let header;
            if (this.props.sortable) {
                const order = this.retrieveOrder(descriptor.attribute);
                const nextOrder = this.nextOrder(order);
                header = (
                    <TableHeader key={id} onClick={() => {this.setState({sortField: descriptor.attribute, sortOrder: nextOrder})}}
                        sortOrder={order}>
                        {descriptor.label}
                    </TableHeader>
                )
            } else {
                header = (
                    <TableHeader key={id}>
                        {descriptor.label}
                    </TableHeader>
                )
            }
            return header;
        });
    };

    renderRows = () => {
        const Row = this.props.customRow || TableRow;
        const values = this.props.sortable ? this.sortedRows() : this.props.value;
        return values.map((value, idx) => (
            <Row key={idx} value={value}>
                {this.props.structure.map((descriptor, id) => (
                    <td key={id}>
                        descriptor.render(value, idx)
                    </td>
                ))}
            </Row>
        ));
    };

    render()  {
        return (
            <table className={this.props.className}>
                <thead>
                    <tr>
                        {this.renderHeaders()}
                    </tr>
                </thead>
                <tbody>
                    {this.renderRows()}
                </tbody>
            </table>
        );
    }
}
导出常量排序\u顺序={
ASC:“上升”,
描述:“下降”,
其他:“其他”
};
类TableRow扩展了React.Component{
render(){
返回(
{this.props.children}
);
}
}
类TableHeader扩展了React.Component{
建造师(道具){
超级(道具);
this.sortIcon=新地图([
[SORT_ORDER.ASC,{icon:sortAsc,title:“升序”},
[SORT_ORDER.DESC,{icon:sortDesc,title:“Descending”},
[SORT_ORDER.OTHER,{icon:sortOther,title:“Unsorted”}]
]);
}
render(){
const{children,onClick,sortOrder}=this.props;
返回(
{onClick(
):children}
);
}
}
导出默认类表扩展React.Component{
建造师(道具){
超级(道具);
此.state={
sortField:props.defaultSortColumn,
sortOrder:props.defaultSortOrder
};
}
检索顺序=(列ID)=>{
return columnId===this.state.sortField?this.state.sortOrder:SORT\u ORDER.OTHER;
};
nextOrder=(当前)=>{
如果(当前===排序顺序.DESC){
返回SORT_ORDER.ASC;
}else if(当前===SORT\u ORDER.ASC){
返回SORT_ORDER.DESC;
}否则{
返回此.props.defaultSortOrder;
}
};
sortedRows=()=>{
让descriptor=this.props.structure.find(d=>d.attribute==this.state.sortField);
让values=this.props.value.slice();
让orderFactor=this.state.sortOrder==SORT\u ORDER.ASC?1:-1;
返回值。排序((a,b)=>{
让我们先来;
让我们再来一次;
//null和未定义的值应更改为空字符串
if(a[描述符.属性]的类型==“编号”| | b[描述符.属性]的类型==“编号”){
first=a[descriptor.attribute]| |“”;
second=b[descriptor.attribute]| |“”;
}否则{
first=描述符。呈现(a)| |“”;
second=descriptor.render(b)| |“”;
}
返回第一个>第二个?orderFactor:first{
返回此.props.structure.map((描述符,id)=>{
让标题;
if(this.props.sortable){
const order=this.retrieveOrder(descriptor.attribute);
const nextOrder=this.nextOrder(订单);
标题=(
{this.setState({sortField:descriptor.attribute,sortOrder:nextOrder}}}
排序器={order}>
{descriptor.label}
)
}否则{
            this.tableStructure = [
                {
                    attribute: "number", label: "Row Number"
                    render: (row) => {return row.number}
                },
                {
                    attribute: "created", label: "Creation time"
                    render: (row) => {return this.dateToString(row.created)}
                },
                {
                    attribute: "type", label: "Row Type"
                    render: (row) => {return row.type}
                },
                {
                    attribute: "state", label: "State",
                    render: (row) => {return row.state}
                },
                {
                    attribute: "action", label: "Action"
                    render: (row) => {
                            return (
                                <button onClick={this.doSomething}>
                                </button>
                            );
                    }
                }
            ];

            <Table structure={this.tableStructure} value={this.state.someValue} sortable
                                        defaultSortColumn="created" defaultSortOrder={SORT_ORDER.DESC} />