refactor: optimize codebase for React 19 compiler (v1.2.6)

React 19 compiler auto-optimizes memoization, making manual hooks unnecessary.

Changes:
- Remove ~60 useCallback/useMemo across 16 files
- Remove React.memo from nav-button and return-button
- Simplify hydration with useSyncExternalStore (privacy-provider)
- Add CHANGELOG.md for version tracking

No functional changes - internal optimization only.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Felipe Coutinho
2026-02-04 13:14:10 +00:00
parent a70a83dd9d
commit 757626c468
18 changed files with 571 additions and 617 deletions

View File

@@ -1,5 +1,5 @@
import type { VariantProps } from "class-variance-authority";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useRef, useState } from "react";
import type { buttonVariants } from "@/components/ui/button";
import {
formatLocaleValue,
@@ -26,9 +26,9 @@ export function useCalculatorState() {
const [copied, setCopied] = useState(false);
const resetCopiedTimeoutRef = useRef<number | undefined>(undefined);
const currentValue = useMemo(() => Number(display), [display]);
const currentValue = Number(display);
const resultText = useMemo(() => {
const resultText = (() => {
if (display === "Erro") {
return null;
}
@@ -39,49 +39,46 @@ export function useCalculatorState() {
}
return formatLocaleValue(normalized);
}, [currentValue, display]);
})();
const reset = useCallback(() => {
const reset = () => {
setDisplay("0");
setAccumulator(null);
setOperator(null);
setOverwrite(false);
setHistory(null);
}, []);
};
const inputDigit = useCallback(
(digit: string) => {
// Check conditions before state updates
const shouldReset = overwrite || display === "Erro";
const inputDigit = (digit: string) => {
// Check conditions before state updates
const shouldReset = overwrite || display === "Erro";
setDisplay((prev) => {
if (shouldReset) {
return digit;
}
if (prev === "0") {
return digit;
}
// Limitar a 10 dígitos (excluindo sinal negativo e ponto decimal)
const digitCount = prev.replace(/[-.]/g, "").length;
if (digitCount >= 10) {
return prev;
}
return `${prev}${digit}`;
});
// Update related states after display update
setDisplay((prev) => {
if (shouldReset) {
setOverwrite(false);
setHistory(null);
return digit;
}
},
[overwrite, display],
);
const inputDecimal = useCallback(() => {
if (prev === "0") {
return digit;
}
// Limitar a 10 dígitos (excluindo sinal negativo e ponto decimal)
const digitCount = prev.replace(/[-.]/g, "").length;
if (digitCount >= 10) {
return prev;
}
return `${prev}${digit}`;
});
// Update related states after display update
if (shouldReset) {
setOverwrite(false);
setHistory(null);
}
};
const inputDecimal = () => {
// Check conditions before state updates
const shouldReset = overwrite || display === "Erro";
@@ -108,40 +105,37 @@ export function useCalculatorState() {
setOverwrite(false);
setHistory(null);
}
}, [overwrite, display]);
};
const setNextOperator = useCallback(
(nextOperator: Operator) => {
if (display === "Erro") {
reset();
const setNextOperator = (nextOperator: Operator) => {
if (display === "Erro") {
reset();
return;
}
const value = currentValue;
if (accumulator === null || operator === null || overwrite) {
setAccumulator(value);
} else {
const result = performOperation(accumulator, value, operator);
const formatted = formatNumber(result);
setAccumulator(Number.isFinite(result) ? result : null);
setDisplay(formatted);
if (!Number.isFinite(result)) {
setOperator(null);
setOverwrite(true);
setHistory(null);
return;
}
}
const value = currentValue;
setOperator(nextOperator);
setOverwrite(true);
setHistory(null);
};
if (accumulator === null || operator === null || overwrite) {
setAccumulator(value);
} else {
const result = performOperation(accumulator, value, operator);
const formatted = formatNumber(result);
setAccumulator(Number.isFinite(result) ? result : null);
setDisplay(formatted);
if (!Number.isFinite(result)) {
setOperator(null);
setOverwrite(true);
setHistory(null);
return;
}
}
setOperator(nextOperator);
setOverwrite(true);
setHistory(null);
},
[accumulator, currentValue, display, operator, overwrite, reset],
);
const evaluate = useCallback(() => {
const evaluate = () => {
if (operator === null || accumulator === null || display === "Erro") {
return;
}
@@ -161,9 +155,9 @@ export function useCalculatorState() {
setOperator(null);
setOverwrite(true);
setHistory(operation);
}, [accumulator, currentValue, display, operator]);
};
const toggleSign = useCallback(() => {
const toggleSign = () => {
setDisplay((prev) => {
if (prev === "Erro") {
return prev;
@@ -177,9 +171,9 @@ export function useCalculatorState() {
setOverwrite(false);
setHistory(null);
}
}, [overwrite]);
};
const deleteLastDigit = useCallback(() => {
const deleteLastDigit = () => {
setHistory(null);
// Check conditions before state updates
@@ -209,9 +203,9 @@ export function useCalculatorState() {
} else if (overwrite) {
setOverwrite(false);
}
}, [overwrite, display]);
};
const applyPercent = useCallback(() => {
const applyPercent = () => {
setDisplay((prev) => {
if (prev === "Erro") {
return prev;
@@ -221,9 +215,9 @@ export function useCalculatorState() {
});
setOverwrite(true);
setHistory(null);
}, []);
};
const expression = useMemo(() => {
const expression = (() => {
if (display === "Erro") {
return "Erro";
}
@@ -240,68 +234,57 @@ export function useCalculatorState() {
}
return formatLocaleValue(display);
}, [accumulator, display, operator, overwrite]);
})();
const buttons = useMemo(() => {
const makeOperatorHandler = (nextOperator: Operator) => () =>
setNextOperator(nextOperator);
const makeOperatorHandler = (nextOperator: Operator) => () =>
setNextOperator(nextOperator);
return [
[
{ label: "C", onClick: reset, variant: "destructive" },
{ label: "⌫", onClick: deleteLastDigit, variant: "default" },
{ label: "%", onClick: applyPercent, variant: "default" },
{
label: "÷",
onClick: makeOperatorHandler("divide"),
variant: "outline",
},
],
[
{ label: "7", onClick: () => inputDigit("7") },
{ label: "8", onClick: () => inputDigit("8") },
{ label: "9", onClick: () => inputDigit("9") },
{
label: "×",
onClick: makeOperatorHandler("multiply"),
variant: "outline",
},
],
[
{ label: "4", onClick: () => inputDigit("4") },
{ label: "5", onClick: () => inputDigit("5") },
{ label: "6", onClick: () => inputDigit("6") },
{
label: "-",
onClick: makeOperatorHandler("subtract"),
variant: "outline",
},
],
[
{ label: "1", onClick: () => inputDigit("1") },
{ label: "2", onClick: () => inputDigit("2") },
{ label: "3", onClick: () => inputDigit("3") },
{ label: "+", onClick: makeOperatorHandler("add"), variant: "outline" },
],
[
{ label: "±", onClick: toggleSign, variant: "default" },
{ label: "0", onClick: () => inputDigit("0") },
{ label: ",", onClick: inputDecimal },
{ label: "=", onClick: evaluate, variant: "default" },
],
] satisfies CalculatorButtonConfig[][];
}, [
applyPercent,
deleteLastDigit,
evaluate,
inputDecimal,
inputDigit,
reset,
setNextOperator,
toggleSign,
]);
const buttons: CalculatorButtonConfig[][] = [
[
{ label: "C", onClick: reset, variant: "destructive" },
{ label: "⌫", onClick: deleteLastDigit, variant: "default" },
{ label: "%", onClick: applyPercent, variant: "default" },
{
label: "÷",
onClick: makeOperatorHandler("divide"),
variant: "outline",
},
],
[
{ label: "7", onClick: () => inputDigit("7") },
{ label: "8", onClick: () => inputDigit("8") },
{ label: "9", onClick: () => inputDigit("9") },
{
label: "×",
onClick: makeOperatorHandler("multiply"),
variant: "outline",
},
],
[
{ label: "4", onClick: () => inputDigit("4") },
{ label: "5", onClick: () => inputDigit("5") },
{ label: "6", onClick: () => inputDigit("6") },
{
label: "-",
onClick: makeOperatorHandler("subtract"),
variant: "outline",
},
],
[
{ label: "1", onClick: () => inputDigit("1") },
{ label: "2", onClick: () => inputDigit("2") },
{ label: "3", onClick: () => inputDigit("3") },
{ label: "+", onClick: makeOperatorHandler("add"), variant: "outline" },
],
[
{ label: "±", onClick: toggleSign, variant: "default" },
{ label: "0", onClick: () => inputDigit("0") },
{ label: ",", onClick: inputDecimal },
{ label: "=", onClick: evaluate, variant: "default" },
],
];
const copyToClipboard = useCallback(async () => {
const copyToClipboard = async () => {
if (!resultText) return;
try {
@@ -320,9 +303,9 @@ export function useCalculatorState() {
error,
);
}
}, [resultText]);
};
const pasteFromClipboard = useCallback(async () => {
const pasteFromClipboard = async () => {
if (!navigator.clipboard?.readText) return;
try {
@@ -364,7 +347,7 @@ export function useCalculatorState() {
} catch (error) {
console.error("Não foi possível colar o valor na calculadora.", error);
}
}, []);
};
useEffect(() => {
return () => {