Eric Jansen
Eric Jansen

Reputation: 440

React update state object using hooks (useState) works, but no rerender

I have a weird problem with React hooks (useState).

I have a page which checks my bills and my bank account and checks wether salary is in, and then moves my money to different jars. The page has 2 buttons: check preconditions (salary enough, etc), and run script.

The first one (preconditions) works as expected, also the output (in below code the var currentstate), when I update the state (with setPreconditions) nothing happens.

So, my thought was that state isnt updated, until I found out that when I changed some other field with state (for example salary) the page rerenders and the correct data for currentstate (state preconditions) is displayed.

Why is this happening?

const Bunq = ({auth}) => {


const [accounts, setAccounts] = useState([]);
const [preconditions, setPreconditions] = useState({run: false, succeeded: false, accountsExist: [], balanceSufficient: true, incomeSufficient: true, sparen: null, maandtotaal: 0, balance: null});
const [rekeningen, setRekeningen] = useState([]);
const [salaris, setSalaris] = useState(getLocalStorage('bunq_salaris') || '');
const [eigen_geld, setEigenGeld] = useState(getLocalStorage('bunq_eigen_geld') || '');
const [sparen, setSparen] = useState(0);
const [page_loaded, setPageLoaded] = useState(false);
const [script_running, setScriptRunning] = useState(false);

useEffect(() => {
    setLocalStorage('bunq_salaris', salaris);
}, [salaris]);

useEffect(() => {
    setLocalStorage('bunq_eigen_geld', eigen_geld);
}, [eigen_geld]);

.......................

const checkPreconditions = () => {
    //check
    //setScriptRunning(true);
    const algemeen_account = getAccountByName("Algemeen");
    let maandnummer = (new Date()).getMonth()+1;
    let currentstate = preconditions;
    currentstate.succeeded = true;
    currentstate.maandtotaal = 0;
    currentstate.incomeSufficient = true;
    currentstate.balanceSufficient = true;

    currentstate.balance = algemeen_account.balance.value;

    rekeningen.map(rekening => {
        currentstate.maandtotaal += rekening["totaal_" + maandnummer];
        let foundaccount = getAccountByName(rekening.rekening);
        if(foundaccount == null && rekening["totaal_" + maandnummer] > 0){
            currentstate.succeeded = false;
            currentstate.accountsExist.push(rekening.rekening)
            console.log("Rekening bestaat niet: " + rekening.rekening);
        }
    });
    if((parseFloat(algemeen_account.balance.value)) < salaris){
        currentstate.balanceSufficient = false;
        currentstate.succeeded = false;
    }
    if((currentstate.maandtotaal + eigen_geld) > salaris){
        currentstate.incomeSufficient = false;
        currentstate.sparen = 0;
        currentstate.succeeded = false;
    }else{
        currentstate.sparen = (salaris - currentstate.maandtotaal - eigen_geld);
        if(currentstate.balanceSufficient){
            currentstate.sparen = (currentstate.sparen + (Math.round(algemeen_account.balance.value) - salaris));
        }
        //console.log(currentstate);
        if(currentstate.sparen < 0){
            currentstate.sparen = 0;
            currentstate.incomeSufficient = false;   
            currentstate.succeeded = false;
        }else{
            currentstate.incomeSufficient = true;
        }

    }

    setPreconditions(currentstate);
    //setPreconditions('test');
    console.log(currentstate, preconditions);
    //setScriptRunning(false);
    //this.setState({preconditions: currentstate});
}

.........................



return (<div><h1>Bunq</h1>
        <DefaultTable data={rekeningen} columns={rekeningColumns} loading={rekeningen.length === 0} pageSize={15}/>
        <Form>
            <Row>
            ......................
            <Button variant="primary" onClick={() => {checkPreconditions();console.log(preconditions);}} disabled={!page_loaded || script_running}>Controleer</Button>

            </Row>
        </Form>

        <ListGroup>
        {JSON.stringify(preconditions)}
            {preconditions.balance !== null ?<ListGroup.Item variant="success">Huidig saldo Algemene rekening: {preconditions.balance}</ListGroup.Item> : ""}
            {preconditions.accountsExist.map((rek, i) => {return <ListGroup.Item  key={i} variant="danger">Rekening {rek} bestaat niet</ListGroup.Item>})}
            {preconditions.balanceSufficient === false ? <ListGroup.Item variant="danger">Niet voldoende saldo. Salaris nog niet binnen?</ListGroup.Item> : ""}
            {preconditions.incomeSufficient === false ? <ListGroup.Item variant="danger">Niet voldoende inkomen om alle rekeningen te betalen</ListGroup.Item> : ""}
            {preconditions.sparen !== null ? <ListGroup.Item variant="success">Er wordt {preconditions.sparen} gespaard</ListGroup.Item> : ""}
        </ListGroup>

    </div>
);

}

Upvotes: 1

Views: 318

Answers (1)

Tholle
Tholle

Reputation: 112777

You are mutating your state, so when you call setPreconditions(currentstate) you are updating the state with the exact same object reference, which React will treat as no state being updated.

You can create a copy of the preconditions object instead.

const checkPreconditions = () => {
  const algemeen_account = getAccountByName("Algemeen");
  let maandnummer = new Date().getMonth() + 1;
  let currentstate = { ...preconditions };

  // ...
}

Upvotes: 2

Related Questions