简体   繁体   English

如何正确更改 object 的 state?

[英]How to change state of object correctly?

I have an object that I would like to change the values when button is clicked.我有一个 object,我想在单击按钮时更改值。 Whatever I do, I am only able to change the state on second click.无论我做什么,我只能在第二次点击时更改 state。 First click is always returning the initial values for me.第一次点击总是为我返回初始值。 Can somebody guide me on what is the problem here?有人可以指导我这里有什么问题吗?

initial state:初始 state:

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

onclick: 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.如果使用以前的 state 计算新的 state,则您可以 [并且应该] 将 function 传递给 setState。 The function will receive the previous value, and return an updated value. function 将接收先前的值,并返回更新的值。

https://reactjs.org/docs/hooks-reference.html#usestate 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.与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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