Supongamos que tengo una devolución de llamada recursiva como esta (pero más compleja):
const weightedFactorial = useCallback(n => { if (n === 0) { return 1; } return weight * n * weightedFactorial(n - 1); },[weight]);¿Hay alguna forma de almacenar valores calculados previamente, de modo que si se llama a la función en un índice repetido, es posible omitir la recursividad?
const value1 = weightedFactorial(60) // Calculate recursively const value2 = weightedFactorial(30) // This value should already be known // and the calculation should be skippedHe intentado mantener un estado con valores conocidos, pero parece que me quedo atascado en un bucle, probablemente porque debe ser una dependencia de la devolución de llamada,
const [knownValues, setKnownValues] = useState([{ n: 0, value: 1 }]); const weightedFactorial = useCallback(n => { const known = knownValues.find(known => known.n === n); if (known?.value) { return known.value; } const newValue = weight * n * weightedFactorial(n - 1); setKnownValues(knownValues => [...knownValues, { n, value: newValue }]); return newValue; },[knownValues, weight]);La forma más fácil de almacenar los resultados para la memorización es un Map o una matriz si el parámetro de su función es un número entero positivo:
function FactorialExamples(props) { const results = [1]; const factorial = n => { if (n in results) return results[n]; // also takes care of our base case n==0 return results[n] = n * factorial(n-1); }; return <p> 5!: { factorial(5) } <br /> 10!: { factorial(10) } </p>; } Esto funcionará bien y no calculará los factoriales más de una vez si llama al factorial varias veces. Sin embargo, aún rehará el cálculo en cada representación de su componente de función. Para conservar los resultados en las nuevas representaciones, mueva la variable de results fuera de la función al alcance del módulo, o colóquela dentro de una referencia (que se almacenará una vez por componente montado):
function Factorial(props) { const results = useRef([1]).current; const factorial = n => { if (n in results) return results[n]; return results[n] = n * factorial(n-1); }; return <p> {props.n}!: { factorial(props.n) } </p>; } function Demo() { const [value, setValue] = useState(0); return <div> <input type="number" value={value} onInput=(e => setValue(e.currentTarget.valueAsNumber)} min="0" /> <Factorial n={value} /> </div>; } Pero tienes un caso más complicado: el weightedFactorial también depende de un estado de weight , no solo de su argumento 1 . Puede restablecer la referencia cada vez que cambia el weight , pero eso es complicado y propenso a errores.
En su lugar, utilice un enfoque similar a su useCallback , que cambia el almacén de resultados junto con la "devolución de llamada". En lugar de useCallback , use useMemo y devuelva un cierre:
const weightedFactorial = useMemo(() => { const results = [1]; return n => { if (n in results) return results[n]; return weight * n * weightedFactorial(n - 1); }; }, [weight]); 1: Por supuesto, podría tratar tanto weight como la n como argumentos, y usar un enfoque estándar para memorizar funciones con múltiples argumentos (ver también aquí ). Luego, los resultados podrían volver a almacenarse estáticamente o en una referencia.
Puede usar React.useMemo para calcular el valor en el primer procesamiento o cuando cambia una dependencia. Pero tal vez se esté refiriendo a la memoization para que un valor calculado previamente no necesite otro cálculo. https://www.30secondsofcode.org/js/s/memoize o https://www.digitalocean.com/community/tutorials/js-understanding-recursion
Puede combinar useMemo y memoization para lograr lo que necesita.