首页 > 解决方案 > 使用 ReactJs 通过 onclick 重新排序列表项

问题描述

学习 ReactJs,我将通过使用最佳实践来实现这一点。请任何人添加其他功能或评论您的解决方案。

我正在尝试通过单击一组向上/向下按钮来构建重新排序列表项组件。

1)如何显示所有道具组件值和他的bgColor?

2) 为了处理事件,我应该使用构造函数并在里面添加 onClickUp() 和 onClickDown() 方法?

FruitList 组件:

class FruitList extends Component {

   constructor(props) {
      super(props);
      this.state = { // set new state for bind key items
         items : [
           {'id': 1, 'name': 'orange', 'bgColor': '#f9cb9c'},
           {'id': 2, 'name': 'lemon','bgColor' : '#fee599'},
           {'id': 3, 'name': 'strawberry', 'bgColor': '#e06666'},
           {'id': 4, 'name': 'apple', 'bgColor' : '#b6d7a7'}
         ]
      }
   }

   onMoveUp = (key) => {
      if(key === 0) return; // disable method when the key its equal to 0 
      const { items } = this.props; // assign props to items for don't repeat my self 
      const index = key - 1;  // save in memory index value less than one
      const itemAbove = items[index]; // save in memory items index  
      items[key - 1] = items[key]; // match id value with the key object
      items[key] = itemAbove; 
      this.setState({ items }); // set new state 
   }

   onMoveDown = (key) => {
      const { items } = this.props;
      if(key === items.length - 1) return;
      const index = key + 1;
      const itemBelow = items[index];
      items[key + 1] = items[key];
      items[key] = itemBelow;
      this.setState({ items });
   }

   render() {
      const { items } = this.state;

      return (
         <ul>
           {items.map((item, key) =>
               <li key={key} style={{ backgroundColor: item.bgColor }}>
                  <div className="fruitsId">{ key + 1 }</div>
                  <div className="fruitsName">{ item.name }</div>
                  <div className="fruitsArrows">
                     <span onClick={() => this.onMoveUp(key)}>&#x25B2;</span>
                     <span onClick={() => this.onMoveDown(key)}>&#x25BC;</span>
                  </div>
               </li>
            )}
         </ul>
      );
   }

}

App.js 组件:

class App extends Component {

   constructor(props) {
      super(props);
      this.state = {
         fruitList : [
           {'id': 1, 'name': 'orange', 'bgColor': '#f9cb9c'},
           {'id': 2, 'name': 'lemon','bgColor' : '#fee599'},
           {'id': 3, 'name': 'strawberry', 'bgColor': '#e06666'},
           {'id': 4, 'name': 'apple', 'bgColor' : '#b6d7a7'}
         ]         
      }
   }

   render() {
      return (
         <FruitList items={this.state.fruitList} />
      );
   }

}

ReactDOM.render(<App />, document.body);

沙盒演示

标签: reactjs

解决方案


是的,您应该提升状态并提供回调onMoveUp/onMoveDown并将它们传递给,FruitList或者您可以拥有一个onMove(id: number, direction: number)并传递到那里+1(enum DOWN) 或-1(enum UP) 以移动正确的方向。请参阅下面的代码。

如果您愿意,也可以将下面代码中的方法handleMove移动到FruitList类中并命名它,handleListChanged这样App每次更改时只会收到新列表。我想我的代码更适合你,因为你是从 React 开始的。

const UP = -1
const DOWN = 1

class FruitList extends React.Component {
   render() {
      const {fruitList, onMove} = this.props

      return (
         <ul>
           {fruitList.map((item) =>
               <li key={item.id} style={{ backgroundColor: item.bgColor }}>
                  <div className="fruitsId">{item.id}</div>
                  <div className="fruitsName">{item.name}</div>
                  <div className="fruitsArrows">
                     <a onClick={() => onMove(item.id, UP)}>&#x25B2;</a>
                     <a onClick={() => onMove(item.id, DOWN)}>&#x25BC;</a>
                  </div>
               </li>
            )}
         </ul>
      );
   }
}

class App extends React.Component {
  state = { // set new state for bind key items
    items: [
      {'id': 1, 'name': 'orange', 'bgColor': '#f9cb9c'},
      {'id': 2, 'name': 'lemon','bgColor' : '#fee599'},
      {'id': 3, 'name': 'strawberry', 'bgColor': '#e06666'},
      {'id': 4, 'name': 'apple', 'bgColor' : '#b6d7a7'},
    ]
  }

  handleMove = (id, direction) => {
    const {items} = this.state

    const position = items.findIndex((i) => i.id === id)
    if (position < 0) {
      throw new Error("Given item not found.")
    } else if (direction === UP && position === 0 || direction === DOWN && position === items.length - 1) {
      return // canot move outside of array
    }

    const item = items[position] // save item for later
    const newItems = items.filter((i) => i.id !== id) // remove item from array
    newItems.splice(position + direction, 0, item)

    this.setState({items: newItems})
  }

  render() {
    return (
      <FruitList fruitList={this.state.items} onMove={this.handleMove} />
    )
  }
}

ReactDOM.render(
  <App />,
  document.body
);
/* Add your css styles here */
body {
    font-family: Arial, Helvetica, sans-serif;
}
ul {
    list-style: none;
    padding: 0;
}
li {
    margin: 0 auto;
    text-align: center;
    width: 400px;
    display: flex;
    align-items: center;    
    justify-content: center;
}
li div {
    border: 1px solid white;
    padding: 5px 0;
}
.fruitsId,
    .fruitsArrows {
    width: 50px;
}
.fruitsName {
    width: 300px;
}
<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>


推荐阅读