1

我正在构建一个应用程序,该应用程序需要对项目表进行排序并根据它们的排序更改它们的 orderNumber。我安装并使用了一个名为 react-dnd 的库来处理排序/排序的功能,到目前为止它工作得很好。我遇到的问题是更新。当用户移动其中一项时,我需要向 api 发送 PUT 请求并更新其 orderNumber。昨晚工作得很好,这是我的代码。

ListItem(正在排序和更新的项目):

import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import {DragSource, DropTarget} from 'react-dnd';
import sdk from '../../js/sdk';
import ItemTypes from './ItemTypes';

const itemSource = {
    beginDrag(props) {
        return {id: props.id};
    }
};

const itemTarget = {
    hover(props, monitor) {
        const draggedId = monitor.getItem().id;
        if (draggedId !== props.id) {
            props.swapItems(draggedId, props.id);
        }
    }
};


const DragSourceDecorator = DragSource(ItemTypes.ITEM, itemSource, (connect, monitor) => {
    return {
        connectDragSource: connect.dragSource(),
        isDragging: monitor.isDragging(),
    };
});

const DropTargetDecorator = DropTarget(ItemTypes.ITEM, itemTarget, (connect) => {
    return {connectDropTarget: connect.dropTarget()};
});

class SwagBagItem extends React.Component {
    constructor(props) {
        super(props);

        this._handleDelete = this._handleDelete.bind(this);
    }

    componentWillReceiveProps(nextProps) {
        const swagbagItemCpy = Object.assign({}, nextProps.swagbagItem);
        delete swagbagItemCpy.id;

        if (nextProps) {
            sdk.put(`swagbags/${nextProps.swagbag.id}/items/${nextProps.swagbagItem.id}`, swagbagItemCpy)
                .done((result) => {
                    console.log(result);
                }).fail((error) => {
                    console.log(error);
                })
            ;
        }
    }

    _handleDelete(event) {
        event.preventDefault();
        event.stopPropagation();

        if (confirm('Are you sure you want to delete this Swagbag Item?')) {
            sdk.delete(`swagbags/${this.props.swagbag.id}/items/${this.props.swagbagItem.id}`)
                .done(() => {
                    console.log('Swagbag Item remove!');
                }).then(() => {
                    this.props.loadSwagBags();
                });
            }
        }

    render() {
        const {swagbagItem} = this.props;
        return this.props.connectDragSource(this.props.connectDropTarget(
            <tr className="swagbag-item">
                <td>{swagbagItem.id}</td>
                <td><Link to={`${this.props.swagbag.id}/items/${swagbagItem.id}`}>{swagbagItem.name}</Link></td>
                <td>{swagbagItem.uri}</td>
                <td>
                    <div className="btn-group btn-group-xs pull-right" role="group">
                        <Link to={`${this.props.swagbag.id}/items/${swagbagItem.id}/edit`} className="btn btn-info">Edit</Link>
                        <Link to={`${this.props.swagbag.id}/items/${swagbagItem.id}`} className="btn btn-info">View</Link>
                        <button className="btn btn-danger btn-xs" onClick={this._handleDelete}>Remove</button>
                    </div>
                </td>
            </tr>
        ));
    }
}


SwagBagItem.propTypes = {
    loadSwagBags: PropTypes.func,
    params: PropTypes.object,
    swagbag: PropTypes.object,
    swagbagItem: PropTypes.object,
};

export default DropTargetDecorator(DragSourceDecorator(SwagBagItem));

包含这些项目的容器或列表:

import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import {DragDropContext} from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import sdk from '../../js/sdk';

import Nav from '../Nav';

import SwagBagItem from '../SwagBagItem';

class SwagBagItemsList extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            swagbag: null,
            swagbagItems: [],
        };

        this._loadSwagBags = this._loadSwagBags.bind(this);
        this._compareItems = this._compareItems.bind(this);
        this._swapItems = this._swapItems.bind(this);
    }

    componentWillMount() {
        this._loadSwagBags();
    }

    _compareItems(item1, item2) {
        return item1.orderNumber - item2.orderNumber;
    }

    _swapItems(itemNo1, itemNo2) {
        const items = this.state.swagbagItems;
        let item1 = items.filter(item => item.id === itemNo1)[0];
        let item2 = items.filter(item => item.id === itemNo2)[0];
        let item1Order = item1.orderNumber;
        item1.orderNumber = item2.orderNumber;
        item2.orderNumber = item1Order;

        items.sort(this._compareItems);
        this.setState({swagbagItems: items});
    }

    _loadSwagBags() {
        sdk.getJSON(`swagbags/${this.props.params.id}`)
            .done((result) => {
                this.setState({swagbag: result});
            })
            .then(() => {
                sdk.getJSON(`swagbags/${this.props.params.id}/items?fields=id,name,summary,uri,itemImageFile,orderNumber`).done((results) => {
                    this.setState({swagbagItems: results});
                });
            });
    }

    render() {
        let swagbagItems = null;
        if (this.state.swagbagItems) {
            swagbagItems = this.state.swagbagItems.map((item) => {
                return <SwagBagItem
                            loadSwagBags={this._loadSwagBags}
                            swagbag={this.state.swagbag}
                            swagbagItem={item}
                            key={item.id}
                            id={item.id}
                            swapItems={this._swapItems}
                        />;
            });
        }
        if (!this.state.swagbag) {
            return <div>Loading...</div>;
        }
        return (
            <div>
                <h1>Swagbag Items</h1>
                <Nav swagbag={this.state.swagbag} />
                <table className="table">
                    <thead>
                        <tr>
                            <th>id</th>
                            <th>name</th>
                            <th>uri</th>
                            <th></th>
                        </tr>
                    </thead>
                    <tbody>
                        {swagbagItems}
                    </tbody>
                </table>
                <Link to={`swagbags/createItem/swagbagid/${this.state.swagbag.id}`} className="btn btn-success">Add Item</Link>
            </div>
        );
    }
}

SwagBagItemsList.propTypes = {
    params: PropTypes.object,
};

export default DragDropContext(HTML5Backend)(SwagBagItemsList);

它正在发出 PUT 请求,但它只移动一个对象就连续发出数百个请求。我不能为我的生活弄清楚为什么。这会严重滞后应用程序并使其无响应。我是否以正确的方式解决这个问题,如果是这样,解决方案是什么?

编辑#1:今天醒来,应用程序运行良好。不幸的是,这正在生产中,所以在此之前我必须重新创建 800+ PUT 请求的错误并解决它。可能会为此提供赏金。

4

1 回答 1

0

如果您想获取它以便在完成拖动后发送更新,您可以将 endDrag 函数添加到 DragSource ( http://gaearon.github.io/react-dnd/docs-drag-source.html )只会触发一次,并且只会在完成拖动后触发。因此,如果您从 componentWillReceiveProps 中删除您的 api 调用并将其移动到源,如下所示:

const itemSource = {
  beginDrag(props) {
    return {
      id: props.id,
      swagbagId: props.swagbag.id,
      swagbagItem: props.swagbagItem,
    };
  },
  endDrag(props, monitor) {
    const item = monitor.getItem();
    sdk.put(`swagbags/${item.swagbagId}/items/${item.swagbagItem.id}`, item.swagbagItem)
       .done((result) => {
           console.log(result);
       }).fail((error) => {
           console.log(error);
       })
    ;
  },
};

它应该只打一次电话(如果不知道 swagbag 和 swagbagItem 中有什么,我无法完全预测,但我认为应该如此)。请注意,我正在使用 DragSource 监视器 ( http://gaearon.github.io/react-dnd/docs-drag-source-monitor.html ) 中的 getItem() 函数来检索 beginDrag 时传入的内容。

于 2016-12-20T21:32:00.760 回答