簡體   English   中英

重新排列對象數組

[英]Reorder array of objects

在我的React狀態下,我想通過始終將選定的對象放在中間,而其他對象保持升序來對3個對象的數組重新排序。

現在,我在每個對象中使用order屬性來跟蹤訂單,但這可能不是最好的方法。

例如 :

this.state = {
  selected: 'item1',
  items: [
    {
      id: 'item1',
      order: 2
    },
    {
      id: 'item2'
      order: 1
    },
    {
      id: 'item3'
      order: 3
    }
  ]
}

結果數組:[item2, item1 ,item3]

現在,讓我們假設用戶選擇了item2 我將相應地更新選定的 state屬性,但是如何更新items屬性以得到如下結果:

this.state = {
  selected: 'item2',
  items: [
    {
      id: 'item1',
      order: 1
    },
    {
      id: 'item2'
      order: 2
    },
    {
      id: 'item3'
      order: 3
    }
  ]
}

結果數組:[item1, item2 ,item3]

你會怎么做? 我看到了一些lodash實用程序函數可能會有所幫助,但我想在普通JavaScript中完成此操作。

我會很懶,只是概述您需要采取的步驟。

  • 從起始數組中彈出所選項目
  • 將起始數組的第一項推入新數組
  • 將所選項目推入新數組
  • 將起始數組的最后一項推入新數組
  • 設置您的狀態以使用新數組

您可以像這樣做一些粗糙的事情:

// Create a local shallow copy of the state
var items = this.state.items.slice()

// Find the index of the selected item within the current items array.
var selectedItemName = this.state.selected;
function isSelectedItem(element, index, array) {
    return element.id === selectedItemName;
};
var selectedIdx = items.findIndex(isSelectedItem);

// Extract that item
var selectedItem = items[selectedIdx];

// Delete the item from the items array
items.splice(selectedIdx, 1);

// Sort the items that are left over
items.sort(function(a, b) {
    return a.id < b.id ? -1 : 1;
});

// Insert the selected item back into the array
items.splice(1, 0, selectedItem);

// Set the state to the new array
this.setState({items: items});

假設items數組的大小始終為3!

您可以執行以下操作:

注意:假定數組中有三個項目,則此方法有效。 但是,如果還有更多,我們只需要在insert函數中指定索引位置即可。

 this.state = {
      selected: 'item1',
      items: [
        {
          id: 'item1',
          order: 1
        },
        {
          id: 'item2',
          order: 2
        },
        {
          id: 'item3',
          order: 3
        }
      ]
    };

    // To avoid mutation.
    const insert = (list, index, newListItem) => [
      ...list.slice(0, index), // part of array before index arg
      newListItem,
      ...list.slice(index) // part of array after index arg
    ];

  // Get selected item object.
    const selectedValue = value => this.state.items.reduce((res, val) => {
      if (val.id === selectedValue) {
        res = val;
      }

      return res;
    }, {});

    const filtered = this.state.items.filter(i => i.id !== state.selected);
    const result = insert(filtered, 1, selectedValue(this.state.selected));

如果存儲項的索引或整個對象的索引而不是存儲針對選定對象的id ,則可以消除多余的reduce

當然,我們需要使用this.setState({ items: result }) 該解決方案還將確保我們在任何時候都不會改變原始狀態數組。

我整理了一個可以擴展的完整示例,以便您可以嘗試不同的方法來實現預期的用例。

在這種情況下,我創建了一個按鈕組件,並渲染了其中的三個,以提供更改所選狀態的方法。

要記住的重要事項,請始終使用setState()函數來更新React Class狀態。 另外,請始終對狀態數組和具有克隆變量的對象進行操作,因為您希望立即更新整個對象/數組。 不要修改指向狀態對象或數組的指針變量的屬性。

通過引用狀態對象/數組,然后通過修改引用對象的指針來更改它們的屬性(偶然地或非偶然地),可以向代碼中添加錯誤。 您將無法保證所有狀態的更新,並且將prevStatenextStatethis.state進行比較可能無法按預期進行。

 /** * @desc Sub-component that renders a button * @returns {HTML} Button */ class ChangeStateButton extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); this.state = ({ //any needed state here }); } handleClick(e) { //calls parent method with the clicked button element and click state this.props.click(e.nativeEvent.toElement.id); } render() { return ( <button id = {this.props.id} name = {this.props.name} className = {this.props.className} onClick = {this.handleClick} > Reorder to {this.props.id}! </button> ); } } /** * @desc Creates button components to control items order in state * @returns {HTML} Bound buttons */ class ReorderArrayExample extends React.Component { constructor(props) { super(props); this.reorderItems = this.reorderItems.bind(this); this.state = ({ selected: 'item1', //added to give option of where selected will insert selectedIndexChoice: 1, items: [ { id: 'item1', order: 2 }, { id: 'item2', order: 1 }, { id: 'item3', order: 3 } ] }); } reorderItems(selected) { const {items, selectedIndexChoice} = this.state, selectedObjectIndex = items.findIndex(el => el.id === selected); let orderedItems = items.filter(el => el.id !== selected); //You could make a faster reorder algo. This shows a working method. orderedItems.sort((a,b) => { return a.order - b.order }) .splice(selectedIndexChoice, 0, items[selectedObjectIndex]); //always update state with setState function. this.setState({ selected, items: orderedItems }); //logging results to show that this is working console.log('selected: ', selected); console.log('Ordered Items: ', JSON.stringify(orderedItems)); } render() { //buttons added to show functionality return ( <div> <ChangeStateButton id='item1' name='state-button-1' className='state-button' click={this.reorderItems} /> <ChangeStateButton id='item2' name='state-button-2' className='state-button' click={this.reorderItems} /> <ChangeStateButton id='item3' name='state-button-2' className='state-button' click={this.reorderItems} /> </div> ); } } /** * @desc React Class renders full page. Would have more components in a real app. * @returns {HTML} full app */ class App extends React.Component { render() { return ( <div className='pg'> <ReorderArrayExample /> </div> ); } } /** * Render App to DOM */ /** * @desc ReactDOM renders app to HTML root node * @returns {DOM} full page */ ReactDOM.render( <App/>, document.getElementById('root') ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> <div id="root"> <!-- This div's content will be managed by React. --> </div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM