如何正确更改对象的状态?

时间:2020-06-28 06:24:36

标签: javascript reactjs

我有一个想要单击按钮时更改其值的对象。无论我做什么,我只能在第二次单击时更改状态。第一次单击总是为我返回初始值。有人可以指导我解决这里的问题吗?

初始状态:

const [currencyResult, setCurrencyResult] = useState({
        amount: "1",
        currencyFrom: "EUR",
        currencyTo: "USD",
        multipliedAmount: "",
        date: ""
    });

onclick:

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;

1 个答案:

答案 0 :(得分:1)

使用功能更新。

如果新状态是使用先前状态计算的,则可以[并且应该]将一个函数传递给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不会自动合并更新对象。