У меня есть страница со списком заказов, каждый из которых имеет уникальный идентификатор заказа. В каждом разделе заказа на странице есть два текстовых поля: одно для trackingID и одно для несущей. Я хотел бы, чтобы мой объект ввода, который обновляется с помощью функции setInput, «помнил» все заказы, которые были обновлены.
Я написал следующий код, но он перезаписывает входную переменную, если я редактирую текстовое поле, принадлежащее другому идентификатору заказа.
const updateStatus = (e) => {
const { id, value, name } = e.target;
if (name === "trackingId") {
setInput((prevState) => ({
...prevState,
orderId: prevState.orderId || id,
shipData: [{ ...prevState.shipData[0], trackingId: value }],
}));
} else if (name === "carrierName") {
setInput((prevState) => ({
...prevState,
orderId: prevState.orderId || id,
shipData: [{ ...prevState.shipData[0], carrierName: value }],
}));
}
console.info(`inputs are: ${JSON.stringify(input)}`);
};
Приведенный выше код создает следующий объект после того, как я отредактирую текстовые поля «carrierName» и «trackingId»:
{"orderId":"1","shipData":[{"carrierName":"carrierOne","trackingId":"TrackingOne"}]}
Вместо этого я хотел бы, чтобы код создавал этот объект, если я редактирую текстовые поля CarrierName и trackingId второго orderId, т. Е. Я хочу, чтобы состояние сохраняло предыдущее состояние:
{"orderId":"1","shipData":[{"carrierName":"carrierOne","trackingId":"TrackingOne"}]},{"orderId":"2","shipData":[{"carrierName":"carrierTwo","trackingId":"TrackingTwo"}]}
По какой-то причине я просто не могу заставить его работать, и я был бы очень признателен за помощь того, кто умнее меня!
🤔 А знаете ли вы, что...
JavaScript - это скриптовый язык программирования, разработанный Netscape Communications Corporation.
Вы перезаписываете свой ввод с помощью setInput
в обоих случаях - состояние, которым вы управляете, является просто объектом, а не массивом, как вы хотите.
Состояние там такое:
{
orderId: number,
shipData: Array<{ trackingValue: string, carrierName: string }>
}
Похоже, что результат, который вы хотите, должен иметь состояние, подобное
Array<{
orderId: number,
shipData: Array<{ trackingValue: string, carrierName: string }>
}>
Позвольте мне предложить быстрое решение - вы, вероятно, захотите индексировать здесь по orderId, а не хранить их в массиве.
Редактировать:
const App = () => {
const [input, setInput] = React.useState({});
const updateShipDataForOrder = (orderId, shipData) => {
setInput((prevState) => {
// Create new ship data based on the previous data + new entry
const newShipData = {
...prevState[orderId],
...shipData,
};
// Overwrite that value in our state
const newState = {
...prevState,
[orderId]: newShipData
};
return newState;
})
}
const updateStatus = (e) => {
const { id, value, name } = e.target;
updateShipDataForOrder(id, { [name]: value })
};
// Convert back to the array you wanted
const result = Object.entries(input).map(([orderId, shipData]) => {
return {
orderId,
shipData
}
})
return (
<div>
<div>
<h1>Order one</h1>
Tracking ID: <input id = "1" name = "trackingId" onChange = {updateStatus} />
Carrier Name: <input id = "1" name = "carrierName" onChange = {updateStatus} />
</div>
<div>
<h1>Order two</h1>
Status: <input id = "2" name = "trackingId" onChange = {updateStatus} />
Carrier Name: <input id = "2" name = "carrierName" onChange = {updateStatus} />
</div>
<br />
<div>result: {JSON.stringify(result, null, '\t')}</div>
</div>
)
}
const root = document.getElementById('root')
ReactDOM.render(<App />, root)
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src = "https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id = "root"></div>