如何在 React-Native 中处理平面列表项的状态

How to handle state on Flat List Items in React-Native

我正在为 React-Native 的 FlatList 组件的项目设置一个计数器。如何在用户每次按下“+”或“-”按钮时更新列表项?

我目前可以更新状态值,但是列表不显示新状态。我已经尝试将 extraData 组件添加到 FlatList,但它似乎并没有更新。

这是数据结构

      data: [
        {
          id: 1,
          name: "Bread",
          price: "400",
          imageS: "../resources/pan-corteza-blanda.jpg",
          quantity: 2
        },
... more data

这是处理增量的函数

  handleIncrement = i => {
    this.setState(state => {
      const formatData = state.data.map((item, j) => {
        console.log("Id", i + " /// " + item.id);
        if (item.id === i) {
          item.quantity = item.quantity + 1;
          return item;
        } else {
          return item;
        }
      });
      console.log("FormatData" + formatData); //Displays the correct  quantity of the item updated

      return {
        formatData
      };
    });
  };

这是列表组件

  <FlatList
          data={this.state.data}
          style={styles.list}
          extraData={this.state.data}
          renderItem={this.renderItem}
        />

我希望在用户每次按下“+”或“-”按钮时使用正确的数量值更新列表项的文本组件。

this.state.data 在您的 handleIncrement 上永远不会改变,这就是您传递给 FlatList 的内容。这就是 FlatList 不更新的原因。

handleIncrement 运行后,您的状态唯一发生变化的是:

{
  formatData: [...stuff here]
}

也许您想传递 this.state.formatData 或在 handleIncrement 中将其重命名为 data

此外,您的状态结构可能更适合用作地图,其中的键是 itemId。这样您就不需要在每次要增加数量时都映射整个列表。

例如

  {

    1: {
      id: 1,
      name: "Bread",
      price: "400",
      imageS: "../resources/pan-corteza-blanda.jpg",
      quantity: 2
    },
    // more data...
  }

现在,您的 handleIncrement 看起来像这样:

handleIncrement = itemId => this.setState(prevState => ({
  ...prevState,
  [itemId]: ++prevState[itemId].quantity
}))

您需要更新数据状态而不是返回项目。

handleIncrement = i => {

  const item = this.state.data[i];

  this.setState({
    data: [
      ...this.state.data.slice(0, i),
      Object.assign({}, this.state.data[i], { quantity: item.quantity + 1 }),
      ...this.state.data.slice(i + 1)
    ]
  });
};

您可以重构函数并将其用于 -+

// pass array index and quantity 1 for + and -1 for -
handleIncrement = (i, qty) => {
  const item = this.state.data[i];

  if (item && item.quantity === 0 && qty === -1) {
    return;
  }

  this.setState({
    data: [
      ...this.state.data.slice(0, i),
      Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
      ...this.state.data.slice(i + 1),
    ],
  });
};

下面是使用上述功能的demo,在reactjs中。该函数也可以在 React Native 中使用。

h1, p {
  font-family: Lato;
}

.container {
  display: flex;
  flex-direction: row;
  border-bottom-style: solid;
  margin-bottom: 5px;
}

.image-container {
  flex-grow: 0;
}

.info-container {
  display: flex;
  margin-left: 10px;
  flex-direction: row;
}

.title {
  margin-top: 0;
}

.titleContainer {
  width: 100px;
}

.cover {
  width: 30px;
}

.buttons {
  flex-grow: 1;
  display: flex;
  margin-left: 10px;
}

.incrementButtons {
  width: 20px;
  height: 20px;
  margin-left: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>

<script type="text/babel">

class Item extends React.Component {
  render() {
    return (
      <div className="container">
        <div className="image-container">
          <img className="cover" src={this.props.image} />
        </div>
        <div className="info-container">
          <div className="titleContainer">
            <p className="title">{this.props.title}</p>
          </div>
          <div className="buttons">
            <p className="title">{this.props.qty}</p>
            <img onClick={() => this.props.increment(this.props.index, -1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/minus-math.png" />
            <img onClick={() => this.props.increment(this.props.index, 1)} className="incrementButtons" src="https://img.icons8.com/metro/26/000000/plus-math.png" />
          </div>
        </div>
      </div>
    )
  }
}

class App extends React.Component {

  state = {
    data: [
      {
        id: 1,
        name: 'Avocado',
        price: '400',
        imageS: 'https://img.icons8.com/metro/26/000000/avocado.png',
        quantity: 0,
      },
      {
        id: 6,
        name: 'Bread',
        price: '300',
        imageS: 'https://img.icons8.com/metro/26/000000/bread.png',
        quantity: 0,
      },
      {
        id: 2,
        name: 'Milk',
        price: '300',
        imageS: 'https://img.icons8.com/metro/26/000000/milk-bottle.png',
        quantity: 0,
      },
    ],
  };

  handleIncrement = (i, qty) => {
    const item = this.state.data[i];

    if (item && item.quantity === 0 && qty === -1) {
      return;
    }

    this.setState({
      data: [
        ...this.state.data.slice(0, i),
        Object.assign({}, this.state.data[i], { quantity: item.quantity + qty, }),
        ...this.state.data.slice(i + 1),
      ],
    });
  };

  render() {

    const items = this.state.data.map((item, index) => (
      <Item qty={item.quantity} index={index} key={index} increment={this.handleIncrement} title={item.name} image={item.imageS} />
    ))
    return (
      <div>
        {items}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
</script>