Как обрабатывать состояние элементов плоского списка в React-Native

Я устанавливаю счетчик для элементов компонента FlatList React-Native. Как я могу обновлять элемент списка каждый раз, когда пользователь нажимает кнопку «+» или «-»?

В настоящее время я могу обновить значение состояния, однако в списке не отображается новое состояние. Я попытался добавить компонент 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}
        />

Я ожидаю обновлять текстовый компонент элемента списка с правильным значением количества каждый раз, когда пользователь нажимает кнопку «+» или «-».


person Alson    schedule 31.05.2019    source источник


Ответы (2)


Вам нужно обновить состояние данных вместо того, чтобы возвращать элемент.

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),
    ],
  });
};

Ниже приведена демонстрация, в которой используется указанная выше функция, она находится в 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>

person Junius L.    schedule 31.05.2019
comment
Если это решение работает для вас, примите мой ответ, щелкнув стрелку вправо рядом с моим ответом. - person Junius L.; 01.06.2019
comment
Идеально! Большое спасибо, мой друг. - person Alson; 03.06.2019
comment
Я столкнулся с подобной проблемой, вы можете проверить этот вопрос, пожалуйста, @JuniusL. stackoverflow.com/questions/57595796/ - person DevAS; 21.08.2019

this.state.data никогда не изменяется на вашем handleIncrement, и это то, что вы переходите в FlatList. Вот почему FlatList не обновляется.

После запуска handleIncrement единственное, что изменится в вашем состоянии:

{
  formatData: [...stuff here]
}

Возможно, вы захотите передать this.state.formatData вместо этого или переименовать его в handleIncrement в data.

Кроме того, ваша структура состояний, вероятно, будет лучше в виде карты, где ключи - это itemIds. Таким образом, вам не нужно отображать весь список каждый раз, когда вы хотите увеличить количество.

e.g.

  {

    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
}))
person Doug    schedule 31.05.2019