Need help with JavaScript Calculator project

Hi, I’m working on the Front End Libraries project for the javascript calculator and I’ve hit a wall. I can’t seem to make the state update properly in my reducer function.

Right now all of my action creators are working, but whenever I hit one of the operator buttons everything seems to sort of break. The formula in the state doesn’t seem to update and remains as undefined. My brain is currently fried from trying to figure this out and I don’t know how to explain it more clearly so here is a screenshot of the console output and the calculator display with a simple calculation, as well as the codepen:

I’m sure there are a ton of other problems with how I’ve written other sections of the program but I’m trying to focus on this as it’s what I’m having the most trouble figuring out currently. For example, I haven’t yet started making any more functions to check the formatting of the formula as I can’t even get the basics of updating the variables in state.

My equals button is also not working but I’m not sure if this is a separate problem with my code or simply because it’s trying to use the null value from the piece of state I can’t update. Thanks in advance for any help!

1 Like

First of all Take a look at your reducers.

case "NUMBER_PRESSED":
      if(state.input == '0')
        return { input: action.payload }
      else
        return { input: state.input + action.payload }

Your updated state will be what you are returning from the reducer.
Here you are returning return { input: action.payload } so your new state will be just

{input: action.payload}

not

{
    input: action.payload,
    expression: '',
    operator: '',
    equalsPressed: false,
    result: ''
}

Thats why you are getting undefined when you press operator.
All cases in your reducer have this problem , the correct way to do this is
return {...state, input: action.payload } - first spread the state and change input

The next problem I found is

 case "EQUALS_PRESSED":
      return {
        equalsPressed: true, 
        expression: state.expression + state.input,
        result: getExpressionResult(state.expression),
        input: '',
        operator: ''
      }

Here you are updating the expression and also calculating the result with the current expression. Remember the state will only update after you returned from the reducer.

Meaning the state.expression when you press equal is “1+”

expression: state.expression + state.input, here you are trying modify it to “1+1”, but remember the state is not modified yet

In the very next line you are evaluating the result result: getExpressionResult(state.expression), , then what will be the argument , its “1+” not “1+1”. You have to fix this

Another one issue is, I think the getExpressionResult function is not doing what it supposed to do. You can evaluate a string expression using the built in eval() function.

1 Like

Hi, thank you for the response!

I think I need to go back and look at the Redux course again because I was under the impression that if you return one piece of state from your reducer it just merges it into the state instead of entirely overwriting the state object. However the Redux documentation seems to agree that the entire state object should be returned each time the reducer function is called.

Adding the spread state to the reducer does seem to have changed the behavior but unfortunately has not solved some of the issues I’m having. The operators I’ve implemented are partially working I think but it seems like the input isn’t being updated in time to actually be added to the expression in time for it to be evaluated. For example, now if I input 111 * 8 and press equals nothing happens, but if I input 111 * 88 it’s being evaluated as 111 * 8 and returning 888. What I’ve been able to see just from messing around with it is that pressing an operator causes the last character from the input to be dropped but I honestly have no idea if this is the case or why it’s happening if it is.

As for my getExpressionResult function, I tested this separately and it seems to work the way it’s supposed to on its own. I gave it the test case on the project page 3 + 5 x 6 - 2 / 4 and it gave the correct formulaic result of 32.5. The reason I implemented it using new Function() instead of eval() was the many negative things I read about using eval regarding security risks that using new Function somewhat mitigates while working very similarly and more efficiently:

There are different types of redux/state/store/reducer etc functionalities and it depends which tool you use. One more contemporary case is the redux toolkit, which on the surface seems to defy all the “rules” we are taught, like dont mutate the state, return the entire state etc. I recently had the chance to dive more into it and it is quite amusing to work with.
When i did JS calculator project, I stayed away from JS built in methods to make calculations. It was important for me to manage to write the logic on my own, instead of using functions like eval(), but thats totally up to preferences.

I’ve managed to make it work! It turns out there was a bug in one of the functions I was using inside of my getExpressionResult function and it would always trim off the last character in my expression.

I ended up having to completely rewrite the operator handling inside of my reducer function to fix a bug that was resetting my expression after more than one operator input. I also ended up changing how the result was rendered in my display to avoid the pitfall of my expression being one input behind when trying to display the result solely with variables pulling data from my state object (e.g., instead of using {result} in my display I would use {getExpressionResult(expression)} to get the result of the most recent expression and still storing the result in my state for further operations).

I then ended up splitting some of the logic from my reducer into helper functions to make it more readable so I could more easily use the correct logic for operator inputs. I looked around online a bit to try and find a more effective way to avoid if/else ladders nested in my reducer function and learned a couple things but ultimately what I did was the simplest way I knew how to make it work. I know it’s not very elegant or concise but it works for every case I tested it for; including fixing a bug that made it break after pressing any button once the equals button was pressed despite it still somehow passing all of the tests from the test suite.

If I had to do this again I would probably just learn to use Math.js for calculating the result like I saw suggested in another thread, and also go back and brush up on Redux state handling in general before attempting this project as it was much more complicated than the previous 3 in terms of handling/updating many pieces of interconnected state.

1 Like