Home > Mobile >  calculate function in calculator not working
calculate function in calculator not working

Time:01-07

export default function App() {
  const [activeKey, setActiveKey] = useState(0);
  const [storeArr, setStoreArr] = useState([]);

  function click(selector) {
    setActiveKey(selector);
    if (activeKey !== "=") {
      setStoreArr([...storeArr, selector]);
      setActiveKey(selector);
    }
  }

  function clear() {
    setStoreArr([]);
    setActiveKey(0);
  }

  function calculate(storeArr) {
    // combine consecutive numbers into a single number
    for (let i = 0; i < storeArr.length; i  ) {
      if (
        typeof storeArr[i] === "number" &&
        typeof storeArr[i   1] === "number"
      ) {
        storeArr[i] = storeArr[i] * 10   storeArr[i   1];
        storeArr.splice(i   1, 1);
        i--;
      }
    }

    // perform multiplication and division first
    for (let i = 0; i < storeArr.length; i  ) {
      if (storeArr[i] === "x") {
        storeArr[i - 1] = storeArr[i - 1] * storeArr[i   1];
        storeArr.splice(i, 2);
        i--;
      } else if (storeArr[i] === "/") {
        storeArr[i - 1] = storeArr[i - 1] / storeArr[i   1];
        storeArr.splice(i, 2);
        i--;
      }
    }

    // perform addition and subtraction
    for (let i = 0; i < storeArr.length; i  ) {
      if (storeArr[i] === " ") {
        storeArr[i - 1] = storeArr[i - 1]   storeArr[i   1];
        storeArr.splice(i, 2);
        i--;
      } else if (storeArr[i] === "-") {
        storeArr[i - 1] = storeArr[i - 1] - storeArr[i   1];
        storeArr.splice(i, 2);
        i--;
      }
    }
    console.log(calculate(storeArr));

    // return the result
    return storeArr[0];
  }

  const topFuncs = [
    {
      name: "clear",
      text: "AC"
    },
    {
      name: "divide",
      text: "/"
    }
  ];

  const numsDiv = [
    {
      name: "seven",
      text: 7
    },
    {
      name: "eight",
      text: 8
    },
    {
      name: "nine",
      text: 9
    },
    {
      name: "four",
      text: 4
    },
    {
      name: "five",
      text: 5
    },
    {
      name: "six",
      text: 6
    },
    {
      name: "one",
      text: 1
    },
    {
      name: "two",
      text: 2
    },
    {
      name: "three",
      text: 3
    },
    {
      name: "zero",
      text: 0
    },
    {
      name: "decimal",
      text: "."
    }
  ];

  const rightDiv = [
    {
      name: "multiply",
      text: "x"
    },
    {
      name: "subtract",
      text: "-"
    },
    {
      name: "add",
      text: " "
    },
    {
      name: "equals",
      text: "="
    }
  ];

  return (
    <div className="App">
      <div id="outer-div" className="outer-div">
        <div className="store-display">{storeArr}</div>
        <div id="display" className="display">
          {activeKey}
        </div>

        <div className="left-right">
          <div id="left-div" className="left-div">
            <div className="top-funcs">
              {topFuncs.map((i) => (
                <button
                  id={i.name}
                  className="btn"
                  key={i.text}
                  onClick={() => {
                    if (i.text === "AC") {
                      return clear();
                    } else {
                      click(i.text);
                    }
                  }}
                >
                  {i.text}
                </button>
              ))}
            </div>
            <div id="nums-div">
              {numsDiv.map((i) => (
                <button
                  id={i.name}
                  className="btn"
                  key={i.text}
                  onClick={() => {
                    click(i.text);
                  }}
                >
                  {i.text}
                </button>
              ))}
            </div>
          </div>
          <div id="right-div" className="right-div">
            {rightDiv.map((i) => (
              <button
                id={i.name}
                className="btn"
                key={i.text}
                onClick={() => {
                  if (i.text === "=") {
                    calculate();
                  } else {
                    click(i.text);
                  }
                }}
              >
                {i.text}
              </button>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

i tried console logging but nothing shows on the console one the button is clicked

TypeError

Cannot read properties of undefined (reading 'length')

but that literally makes no sense to me, it doesnt understand what .length means?

CodePudding user response:

Shadowing a variable is an error waiting to happen. Which is exactly what you're doing here:

function calculate(storeArr) {

Within the scope of that function, storeArr doesn't refer to the state value. It refers to the argument passed to the function. And what argument do you pass to the function? Nothing at all:

onClick={() => {
  if (i.text === "=") {
    calculate(); // <--- here
  } else {
    click(i.text);
  }
}}

So within the function, storeArr is undefined. And, exactly as the error is telling you, you can't read a property from undefined.

Edit: Don't Mutate State Either

I just noticed that within your calculate function you are modifying the array. Never mutate state in React. So in this case it sounds like you need to:

  1. Actually pass a value to your function.
  2. Pass that value as a new array, not the existing state value.
  3. Rename the local variable in the function, since it's confusing you.

So call the function with the new array:

onClick={() => {
  if (i.text === "=") {
    calculate([...storeArr]); // <--- here
  } else {
    click(i.text);
  }
}}

(Additionally, at least for future readers, also make sure that if this is an array of objects that you don't mutate any of the objects in the new array, since they're the same object references back to state. Deep cloning arrays/objects is another matter altogether.)

And give the local variable a different name:

function calculate(sArr) {

And, of course, update all references within the function to the new local variable and not the state variable.

As an added improvement, since the function relies only on what is passed to it and not on component state, move the function outside of the component. It can be its own module, or just outside the component within the same module. This will further avoid confusion as it makes it more clear that the function is usable in isolation and not dependent on component state.


Original Answer:

Don't shadow the variable:

function calculate() {

That way within the function you're referring to the state value, not a local variable. And you can then remove the unnecessary argument from other uses of the function. So this:

console.log(calculate(storeArr));

Can become this:

console.log(calculate());

After all, why would you need to pass a value to a function which already exists within the same scope and can already access that value?

If you do want to pass a value to the function, give the function's local variable(s) a different name than one you're already using.

CodePudding user response:

You're getting the error because your calculate function expects one argument, but you're not passing it anything in your onClick handler:

onClick={() => {
                  if (i.text === "=") {
                    calculate();
                  } else {
                    click(i.text);
                  }
                }}

This causes the storeArr argument in the calculate function to equal undefined, so then when you try iterating over it in the for loop, it throws an error because you can't access the .length property on an undefined value.

  • Related