Как отключить только выбранную кнопку onClick inside .map() функции REACT js

#javascript #reactjs #onclick #setstate #map-function

#javascript #reactjs #onclick #setstate #map-функция

Вопрос:

У меня есть приложение для покупок в REACT js. Я показываю все товары с помощью функции .map(), а также показываю кнопку «ДОБАВИТЬ в корзину» перед каждым товаром. При нажатии кнопки ДОБАВИТЬ в корзину btn добавляется выбранный идентификатор продукта в локальном хранилище, после чего я отображаю эти выбранные товары в корзине покупок, извлекая идентификаторы из localStorage. Все работает нормально.

Теперь я хотел отключить кнопку «ДОБАВИТЬ в корзину» (только для выбранного товара) при нажатии на нее один раз. Я сделал это, установив state, но на самом деле он отключает ВСЕ кнопки «ДОБАВИТЬ в корзину» перед всеми ПРОДУКТАМИ вместо отключения только выбранной кнопки.

Я много искал эту проблему, и решение, которое я получил везде, — это просто установить значение true / false для включения / выключения кнопки. Я сделал это, но бесполезно, потому что он делает это для ВСЕХ продуктов на этой странице. Пожалуйста, помогите мне, что делать.

Вот мой код REACT JS:

 export default class SpareParts extends Component
{
  constructor()
  {
      super()
      this.state = {
        spareParts: [],
        cart: [],
        inCart: false,
        disabledButton: false
      };

      this.ViewDeets = this.ViewDeets.bind(this);
      this.AddToCart = this.AddToCart.bind(this);
  }


  ViewDeets= function (part)
  {
    this.props.history.push({
                pathname: '/partdetails',
                 state: {
                    key: part
                }
            });
  }

  AddToCart(param, e)
  {
  
    var alreadyInCart = JSON.parse(localStorage.getItem("cartItem")) || [];
    alreadyInCart.push(param);
    localStorage.setItem("cartItem", JSON.stringify(alreadyInCart));

    this.setState({
      inCart: true,
      disabledButton: true
    })

  }

  
  componentDidMount()
  {
    console.log("Showing All Products to Customer");

        axios.get('http://localhost/Auth/api/customers/all_parts.php', {
        headers: {
         'Accept': 'application/json, text/plain, */*',
          'Content-Type': 'application/json'
         }} )
       .then(response =>
       {
       this.setState({
              spareParts :response.data.records
            });
       })
         .catch(error => {
         if (error) {
           console.log("Sorry Cannot Show all products to Customer");
           console.log(error);
         }
           });
  }

render()
  {
    return (

<div id="profileDiv">

{this.state.spareParts.map(  part =>


<Col md="3" lg="3" sm="6" xs="6">
  <Card>

  <Image src={"data:image/png[jpg];base64,"    part.Image}
  id="partImg" alt="abc" style={ {width: "90%"}} />

  <h4>  {part.Name} </h4>
  <h5> Rs. {part.Price}  </h5>
  <h5> {part.Make} {part.Model} {part.Year} </h5>
  <h5> {part.CompanyName} </h5>

<button
    onClick={()=> this.ViewDeets(part) }>
    View Details
</button>

<button onClick={() => this.AddToCart(part.SparePartID)}
   
   disabled={this.state.disabledButton ? "true" : ""}>
  {!this.state.inCart ? ("Add to Cart") : "Already in Cart"}
</button>

  </Card>
</Col>

)}

</div>

);
  }
} 

Ответ №1:

Вам нужно отключать только одну кнопку за раз? Если это так, измените свое состояние на не логическое значение, а число, указывающее, какая кнопка отключена. Затем при рендеринге отключайте только в том случае, если отображаемая вами кнопка имеет тот же индекс, что и в состоянии.

 this.state = {
   disabledButton: -1
   // ...
}

// ...

AddToCart(index, param, e) {
  //...
  this.setState({
    inCart: true,
    disabledButton: index
  })
}


// ...

{this.state.spareParts.map((part, index) => {
   // ...
  <button onClick={() => this.AddToCart(index, part.SparePartID)}
    disabled={this.state.disabledButton === index}>
    {!this.state.inCart ? ("Add to Cart") : "Already in Cart"}
  </button>
})}
 

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

 this.state = {
  spareParts: [],
  disabledButtons: [],
  // ...
}

// ...

axios.get('http://localhost/Auth/api/customers/all_parts.php', {
  headers: {
    'Accept': 'application/json, text/plain, */*',
    'Content-Type': 'application/json'
    }} )
.then(response =>{
  this.setState({
    spareParts: response.data.records,
    disabledButtons: new Array(response.data.records.length).fill(false)
  });
});

// ...

AddToCart(index, param, e) {
  //...
  this.setState(oldState => {
    const newDisabledButtons = [...oldState.disabledButtons];
    newDisabledButtons[index] = true;
    return {
      inCart: true,
      disabledButtons: newDisabledButtons,
    }
  });
}

// ...

{this.state.spareParts.map((part, index) => {
   // ...
  <button onClick={() => this.AddToCart(index, part.SparePartID)}
    disabled={this.state.disabledButtons[index]>
    {!this.state.inCart ? ("Add to Cart") : "Already in Cart"}
  </button>
})}

 

Комментарии:

1. Спасибо за ответ. Да, я хочу отключить каждую кнопку независимо одновременно. Итак, как мне изменить состояние на массив логических значений? Пожалуйста, уточните.

2. @YellowMinion я добавил в пример с массивом

3. Еще раз спасибо. Как мне отключить эту нажатую кнопку в методе AddToCart?

4. Вы устанавливаете состояние с помощью массива, для которого этот индекс переключен на true . Я отредактировал пример.

5. Удивительный и очень полезный ответ. Именно то, что я искал, но почему-то я не понимаю, как я мог бы немедленно обновить кнопку. У меня есть таблица с большим количеством кнопок, и они повторно отображаются только тогда, когда я щелкаю из строки вместо этого после нажатия кнопки. Любые советы, как запустить повторный рендеринг кнопки, которая теперь должна быть отключена?