[英]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狀態。 另外,請始終對狀態數組和具有克隆變量的對象進行操作,因為您希望立即更新整個對象/數組。 不要修改指向狀態對象或數組的指針變量的屬性。
通過引用狀態對象/數組,然后通過修改引用對象的指針來更改它們的屬性(偶然地或非偶然地),可以向代碼中添加錯誤。 您將無法保證所有狀態的更新,並且將prevState
或nextState
與this.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.