
Creando una calculadora bƔsica usando React JS y TypeScript
React JS
React JS es una librerĆa de JavaScript muy popular usada para el diseƱo de interfaces de usuario, una de las caracterĆsticas mĆ”s importantes de React es que permite separar en componentes los elementos de una pĆ”gina, esta fragmentación de componentes permite reutilizar código asĆ como trabajar solo en secciones de una pĆ”gina sin necesidad de recargar todo el documento nuevamente, esta librerĆa es soportada por Facebook y una gran comunidad de desarrolladores lo que la vuelve muy estable y popular.
TypeScript
El uso de TypeScript permite darle mayor estabilidad al incorporar tipos de datos dentro de JavaScript como una especie de lenguaje de programación "tipado", TypeScript es un lenguaje de programación libre y de código abierto desarrollado y mantenido por Microsoft. Es un superconjunto de JavaScript, que esencialmente añade tipos estÔticos y objetos basados en clases.
Código
Components
src/Components/Calculator.tsx
import CalculatorScreen from "./CalculatorScreen";
import CalculatorState from "./CalculatorState";
import Button from "./Button";
import "../Assets/styles.css";
export default function Calculator() {
return (
<CalculatorState>
<div className="calculatorContainer">
<CalculatorScreen />
<div className="container">
<Button type="action" value="AC" />
<Button type="operator" value="%" />
<Button type="action" value="←" />
<Button type="operator" value="/" />
<Button type="number" value="7" />
<Button type="number" value="8" />
<Button type="number" value="9" />
<Button type="operator" value="*" />
<Button type="number" value="4" />
<Button type="number" value="5" />
<Button type="number" value="6" />
<Button type="operator" value="-" />
<Button type="number" value="1" />
<Button type="number" value="2" />
<Button type="number" value="3" />
<Button type="operator" value="+" />
<Button type="action" value="+/-" />
<Button type="number" value="0" />
<Button type="action" value="." />
<Button type="action" value="=" />
</div>
</div>
</CalculatorState>
);
}
src/Components/CalculatorScreen.tsx
import { useAppContext } from "./CalculatorState";
export default function CalculatorScreen() {
const calculator = useAppContext();
return (
<div className="calculatorScreen">
<div className="calculatorCurrentValue">
{calculator.currentValue}
{calculator.isDecimal && "."}
</div>
</div>
);
}
src/Components/Button.tsx
import { useAppContext } from "./CalculatorState";
export default function Button({
type,
value,
}: {
type: string;
value: string;
}) {
const calculator = useAppContext();
const handleClick = () => {
switch (type) {
case "number":
calculator.addNumber(Number(value));
break;
case "operator":
calculator.addOperation(value);
break;
case "action":
calculator.executeAction(value);
break;
default:
break;
}
};
return (
<button className="calculatorButton" onClick={handleClick}>
{value}
</button>
);
}
src/Components/CalculatorState.tsx
import { createContext, useState, useContext } from "react";
const AppContext = createContext({
/* state */
memory: null,
operation: null,
currentValue: 0,
isDecimal: false,
/* methods */
addNumber: (value: number | string) => {},
addOperation: (operation: string) => {},
getResult: () => {},
executeAction: (action: string) => {},
});
export default function CalculatorState({ children }: any) {
const [memory, setMemory] = useState(null);
const [operation, setOperation] = useState(null);
const [currentValue, setCurrentValue] = useState(0);
const [isReset, setIsReset] = useState(true);
const [isDecimal, setIsDecimal] = useState(false);
const handleAddNumber = (value: number | string) => {
if (isReset) {
if (value.toString() === ".") {
setIsDecimal(true);
} else {
const dot = isDecimal ? "." : "";
const old: string = currentValue.toString() + dot + value.toString();
setCurrentValue(parseFloat(old));
setIsReset(false);
setIsDecimal(false);
}
} else {
if (value.toString() === ".") {
setIsDecimal(true);
} else {
const dot = isDecimal ? "." : "";
const old: string = currentValue.toString() + dot + value.toString();
setIsDecimal(false);
setCurrentValue(parseFloat(old));
}
}
};
const handleAddOperation = (op: string) => {
if (currentValue) {
if (operation) {
handleGetResult();
setOperation(op);
setIsReset(true);
setIsDecimal(false);
} else {
setOperation(op);
setMemory(currentValue);
setCurrentValue(0);
setIsReset(true);
setIsDecimal(false);
}
}
};
const handleGetResult = () => {
let result = 0;
if (currentValue && operation && memory) {
switch (operation) {
case "+":
result = parseFloat(currentValue.toString()) + parseFloat(memory);
break;
case "-":
result = parseFloat(memory) - parseFloat(currentValue.toString());
break;
case "*":
result = parseFloat(memory) * parseFloat(currentValue.toString());
break;
case "/":
result = parseFloat(memory) / parseFloat(currentValue.toString());
break;
case "%":
result =
(parseFloat(memory) / 100) * parseFloat(currentValue.toString());
break;
default:
}
setCurrentValue(result);
setOperation(null);
setMemory(result);
setIsReset(true);
setIsDecimal(false);
}
};
const clean = () => {
setCurrentValue(0);
setOperation(null);
setIsReset(true);
setIsDecimal(false);
};
const deleteNumber = () => {
const index = currentValue.toString().indexOf(".");
if (index > 0) {
const numberOfDecimals = currentValue.toString().slice(index + 1).length;
if (numberOfDecimals == 1) {
const min = Math.floor(currentValue);
setCurrentValue(min);
} else {
const newNumber = currentValue.toString().substring(0, currentValue.toString().length-1);
setCurrentValue(parseFloat(newNumber.toString()));
}
} else {
setCurrentValue(Math.floor(currentValue / 10));
}
};
const addDecimal = () => {
if (currentValue.toString().indexOf(".") > 0) {
} else {
handleAddNumber(".");
}
};
const handleExecuteAction = (action: string) => {
switch (action) {
case "=":
handleGetResult();
break;
case "AC":
clean();
break;
case "←":
deleteNumber();
break;
case "+/-":
setCurrentValue(currentValue * -1);
break;
case ".":
addDecimal();
break;
default:
}
};
return (
<AppContext.Provider
value={{
memory,
operation,
currentValue,
isDecimal,
addNumber: handleAddNumber,
addOperation: handleAddOperation,
getResult: handleGetResult,
executeAction: handleExecuteAction,
}}
>
{children}
</AppContext.Provider>
);
}
export function useAppContext() {
return useContext(AppContext);
}