javascript - 如何正确更改对象的状态?
问题描述
我有一个对象,我想在单击按钮时更改值。无论我做什么,我只能在第二次点击时改变状态。第一次点击总是为我返回初始值。有人可以指导我这里有什么问题吗?
初始状态:
const [currencyResult, setCurrencyResult] = useState({
amount: "1",
currencyFrom: "EUR",
currencyTo: "USD",
multipliedAmount: "",
date: ""
});
点击:
setCurrencyResult({
amount: currencyResult.amount,
currencyFrom: currencyResult.currencyFrom,
currencyTo: currencyResult.currencyTo,
multipliedAmount: currencyRate * currencyResult.amount,
date: Date.now()
})
整个代码是:
import React, { useState, useEffect } from 'react';
import { Form, Icon } from 'semantic-ui-react';
import { Link } from 'react-router-dom';
import ShowResult from './ShowResult';
import "../styles/HomePage.css"
const HomePage = (props) => {
const options = [
{ key: 'EUR', value: 'EUR', text: 'EUR' },
{ key: 'USD', value: 'USD', text: 'USD' },
{ key: 'CHF', value: 'CHF', text: 'CHF' },
];
const baseUrl = `https://api.exchangeratesapi.io/latest?base=`
const [currencyResult, setCurrencyResult] = useState({
amount: "1",
currencyFrom: "EUR",
currencyTo: "USD",
multipliedAmount: "",
date: ""
});
const [currencyDatabase, setCurrencyDatabase] = useState([]);
const [hasError, setHasError] = useState(false);
const [errorMessage, setErrorMessage] = useState("");
const { amount, currencyFrom, currencyTo, multipliedAmount, date } = currencyResult;
const [currencyRate, setCurrencyRate] = useState("");
const [clicked, setClicked] = useState(false);
const formValidation = () => {
if (currencyResult.currencyFrom === currencyResult.currencyTo) setErrorMessage("Equal currencies")
if (!currencyResult.amount) setErrorMessage("no number given")
if (currencyResult.amount.charAt[0] === "-") setErrorMessage("no minus numbers")
if (currencyResult.amount === "0") setErrorMessage("can't convert 0")
if (errorMessage) setHasError(true)
}
const calculationHandler = async () => {
formValidation()
if (hasError) {
return
} else {
setClicked(!false)
const fetchData = await fetch(`${baseUrl}${currencyResult.currencyFrom}&symbols=${currencyResult.currencyTo}`);
const response = await fetchData.json();
setCurrencyRate(await Object.values(response.rates)[0])
setCurrencyDatabase([...currencyDatabase, currencyResult])
setCurrencyResult({
amount: currencyResult.amount,
currencyFrom: currencyResult.currencyFrom,
currencyTo: currencyResult.currencyTo,
multipliedAmount: currencyRate * currencyResult.amount,
date: Date.now()
})
}
}
if (currencyDatabase) props.getCalculations(currencyDatabase);
const changeCurrency = () => {
setCurrencyResult({
...currencyResult,
currencyTo: currencyResult.currencyTo
})
setCurrencyResult({
...currencyResult,
currencyFrom: currencyResult.currencyFrom
})
}
return (
<div className="app">
<div className="header">
<h1 className="headline">Convert currencies in real-time.</h1>
</div>
<div className="form-content">
<Form className="box-background">
<Form.Group style={{ margin: "auto" }} >
<Form.Input
required
label='Amount'
placeholder='Amount'
value={currencyResult.amount}
onChange={(e, { value }) => setCurrencyResult({
...currencyResult,
amount: value
})}
type="number"
/>
<Form.Select
required
placeholder="From"
label="From"
value={currencyResult.currencyFrom}
onChange={(e, { value }) => setCurrencyResult({
...currencyResult,
currencyFrom: value
})}
options={options}
/>
<Icon name="exchange" onClick={changeCurrency} size="large" />
<Form.Select
required
placeholder="To"
label="To"
value={currencyResult.currencyTo}
onChange={(e, { value }) => setCurrencyResult({
...currencyResult,
currencyTo: value
})}
options={options}
/>
<Form.Button
className="btn-div"
onClick={calculationHandler}>
Convert
</Form.Button>
</Form.Group>
<Form.Field className="error-msg">
{hasError ? <p>{errorMessage}</p> : null}
</Form.Field>
</Form>
<Link to="/result" className="conversion-history">
<span>View conversion history {">"}</span>
</Link>
</div>
{currencyResult && <ShowResult currencyResult={currencyResult} />}
</div>
);
}
export default HomePage;
解决方案
使用功能更新。
如果新状态是使用前一个状态计算的,您可以 [并且应该] 将一个函数传递给 setState。该函数将接收先前的值,并返回一个更新的值。
https://reactjs.org/docs/hooks-reference.html#usestate
const calculationHandler = async () => {
// async stuff
setCurrencyResult(previous => {
return {
amount: previous.amount,
currencyFrom: previous.currencyFrom,
currencyTo: previous.currencyTo,
multipliedAmount: currencyRate * previous.amount,
date: Date.now()
}
})
}
}
与类组件中的 setState 方法不同,useState 不会自动合并更新对象。
推荐阅读
- python - 如何对 csv 文件进行排序以仅在文件中获取一行?
- node.js - 无法成功将视频上传到 AWS S3
- android - ANDROID - FIREBASE - 不支持序列化集合
- scala - How can I block terminating my program until the Observable consumption is complete?
- android - 致命异常:OkHttp 调度程序进程:java.lang.BootstrapMethodError:来自调用站点#1 引导方法的异常
- flutter - 颤动中的居中按钮问题
- javascript - 无法将 react-select 样式设置为引导 sm
- docker - 如何在容器内获取 docker 系统 ID?
- c - 使用 getchar() 清除 Stdin 后输入的换行问题 [已解决]
- python - 如何选择/过滤具有空列表的 Pandas 列?