简体   繁体   中英

How to change state of object correctly?

I have an object that I would like to change the values when button is clicked. Whatever I do, I am only able to change the state on second click. First click is always returning the initial values for me. Can somebody guide me on what is the problem here?

initial state:

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()
            })

whole code is:

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;

Use functional updates.

If the new state is computed using the previous state, you can [and should] pass a function to setState. The function will receive the previous value, and return an updated value.

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()
            }
        })
    }
}

Unlike the setState method found in class components, useState does not automatically merge update objects.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM