Ручной ввод с одинаковой государственной стоимостью

RogerFedFan спросил: 12 мая 2018 в 04:20 в: javascript

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

Я попробовал добавить на вход поле имени и установить мое начальное состояние в undefined, и это работает отлично, но числа не проходят.

Как мы обрабатываем входные данные, чтобы быть разными, когда они имеют одно и то же значение состояния? Или это невозможно / немой?

class App extends Component {
  state = {
    items: {
      1: {
        id: 1, name: 'Yeezys', price: 300, remaining: 5
      },        2: {
        id: 2, name: 'Github Sweater', price: 50, remaining: 5
      },      3: {
        id: 3, name: 'Protein Powder', price: 30, remaining: 5
      }
    },
    itemQuantity: 0
  },  render() {
    return (
      <div>
        <h1>Shopping Area</h1>
        {Object.values(items).map(item => (
          <div key={item.id}>
            <h2>{item.name}</h2>
            <h2>$ {item.price}</h2>
            {item.remaining === 0 ? (
              <p style={{ 'color': 'red' }}>Sold Out</p>
            ) : (
              <div>
                <p>Remaining: {item.remaining}</p>
                <input 
                  type="number"
                  value={ itemQuantity }
                  onChange={e => this.setState({ itemQuantity: e.target.value})}
                  placeholder="quantity"
                  min={1}
                  max={5}
                />
                <button onClick={() => this.addItem(item)}>Add To Cart</button>
              </div>
            )}
          </div>
        ))}
      </div>
    )
  }
}

5 ответов

Есть решение
ionizer ответил: 13 мая 2018 в 07:41

Это решение, которое проблема свободно интерпретируется, но она работает без необходимости создания другого компонента. Как вы знаете, вам нужно было разделить состояние каждого предмета в тележке. Я сделал это, динамически инициализируя и устанавливая состояния количества каждого элемента. Вы можете увидеть изменения состояния в этом примере:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { quantities: {} }
  }

  componentDidMount() {
    let itemIDs = ['1', '2', '3', 'XX']; //use your own list of items
    itemIDs.forEach(id => {
      this.setState({quantities: Object.assign(this.state.quantities, {[id]: 0})});
    })
  }

  render() {
    let list = Object.keys(this.state.quantities).map(id => {
      return (
        <div>
          <label for={id}>Item {id}</label>
          <input
            id={id}
            key={id}
            type="number"
            value={this.state.quantities[id]}
            onChange={e => {
              this.setState({quantities: Object.assign(this.state.quantities, {[id]: e.target.value})})
            }}
          />
        </div>
      );
    })
    return (
      <div>
        {list}
        <div>STATE: {JSON.stringify(this.state)}</div>
      </div>
    );
  }
}

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'></div>

Вы можете изменить состояние по вашему вкусу.

RogerFedFan ответил: 12 мая 2018 в 07:26
Закончился с вашим ответом, когда я пошел вперед и применил свойство количества к каждому из моих предметов и ставлю целевое значение. Благодаря! :)
Kishan Mundha ответил: 12 мая 2018 в 04:32

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

Для достижения цели вы можете создать компонент для элемента списка и сохранить состояние в компоненте элемента списка. Поскольку каждый компонент имеет собственное состояние, значение состояния не будет конфликтовать.

Вот пример

class CardItem extends Component {
    state = {
        number: 0
    }    render() {
        render (
            <input type="text" value={this.state.number} onChange={e => this.setState({ number: e.target.value })} />
        )
    }
}class Main extends Component {
    render () {
        const list = [0,1,2,3,4]        return (
            list.map(item => <CardItem data={item} />)
        )
    }
}
RogerFedFan ответил: 12 мая 2018 в 04:34
Должен был подумать об этом. Спасибо.
Chase DeAnda ответил: 12 мая 2018 в 04:41

Вот как я обычно обрабатываю этот сценарий. Вы говорите, что получаете массив предметов? Каждый объект объекта должен содержать ключ для сохранения значения (count в моем примере). Вы можете использовать общий обработчик onChange для обновления отдельного элемента в массиве. Итак, теперь ваше состояние управляет списком элементов вместо каждого отдельного входного значения. Это делает ваш компонент более гибким, и он сможет обрабатывать любое количество элементов без изменений кода:

const itemData = [
{ id: 0, count: 0, label: 'Number 1' },
{ id: 1, count: 0, label: 'Number 2' },
{ id: 2, count: 0, label: 'Number 3' },
{ id: 3, count: 0, label: 'Number 4' }
];

class App extends React.Component {

  state = {
    items: itemData
  }
  
  handleCountChange = (itemId, e) => {
    // Get value from input
    const count = e.target.value;
    this.setState( prevState => ({
      items: prevState.items.map( item => {
        // Find matching item by id
        if(item.id === itemId) {
          // Update item count based on input value
          item.count = count;
        }
        return item;
      })
    }))
  };
  
  renderItems = () => {
    // Map through all items and render inputs
    return this.state.items.map( item => (
       <label key={item.label}>
          {item.label}:
          <input
            type="number"
            value={item.count}
            onChange={this.handleCountChange.bind(this, item.id)}
          />
        </label>
    ));
  };

  render() {
    return (
      <div>
       {this.renderItems()}
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
label {
  display: block;
}
<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"></div>
Bruno Mazzardo Matheus Pitz ответил: 12 мая 2018 в 04:39

Вы не можете использовать одно и то же состояние для обоих входов. Попробуйте использовать другое состояние для каждого из них:

class App extends Component {state = {
    number: ""
  }  render() {
    return (
      <div>
        <input
          type="number"
          value={this.state.number}
          onChange={e => this.setState({ number: e.target.value })}
        />
        <input
          type="number"
          value={this.state.number2}
          onChange={e => this.setState({ number2: e.target.value })}
        />
      </div>
    )
  }
}