# React js
## useContext
Context provee una forma de pasar datos a través del árbol de componentes sin tener que pasar props manualmente en cada nivel.
Context está diseñado para compartir datos que pueden considerarse “globales” para un árbol de componentes en React, como el usuario autenticado actual, el tema o el idioma preferido
```
const value = useContext(MyContext);
```
Un componente que llama a useContext siempre se volverá a renderizar cuando el valor del contexto cambie. Si volver a renderizar el componente es costoso, puedes optimizar esto usando memorización.
https://github.com/facebook/react/issues/15156#issuecomment-474590693
ejemplo useContext y useMemo
```
import React, { createContext, useState } from 'react'
// No es necesario definir el valor deseado, solo inicializarlo con un valor vacio
const DateContext = createContext({
contextInitialValues: '',
otrosValues: true,
etc: () => {}
})
//Declaramos children para envolver los componentes con el provider => mas abajo
interface Props {
children: React.ReactNode
}
export const DateContextProvider = (props: Props) => {
// creamos cualquier estado que deseemos
const [estado, setEstado] = useState(false)
//cualquier logica para modificar dicho estado
const openCalendarModal = () => setEstado(true)
const getDayById = (id: string): Type => {
return stado.find(day => day.id === id)
}
//retornamos el provider y los valores/funciones que deseamos exponer
return <DateContext.Provider value={{
estado,
openCalendarModal,
getDayById
}}>{props.children}</DateContext.Provider>
}
export default DateContext
const Componente = (props) => {
const nameContext = useContext(DateContext)
return (
div..
{nameContext.estado}
...
)
}
<DateContextProvider>
<Componente />
</DateContextProvider>
```
## useReducer
> useReducer a menudo es preferible a useState cuando se tiene una lógica compleja que involucra múltiples subvalores o cuando el próximo estado depende del anterior. useReducer además te permite optimizar el rendimiento para componentes que activan actualizaciones profundas, porque puedes pasar hacia abajo dispatch en lugar de callbacks.
```
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
```
> React garantiza que la identidad de la función dispatch es estable y no cambiará en subsecuentes renderizados. Es por eso que es seguro omitirla de la lista de dependencias de useEffect o useCallback.
>
# useCallback
const memoizedCallback =
useCallback(() => {
doSomething(a, b);
},[a, b],);
Pasa un callback en línea y un arreglo de dependencias. useCallback devolverá una versión memorizada del callback que solo cambia si una de las dependencias ha cambiado. Esto es útil cuando se transfieren callbacks a componentes hijos optimizados que dependen de la igualdad de referencia para evitar renders innecesarias (por ejemplo, shouldComponentUpdate).
# useMemo
`const memoizedValue =
useMemo(() => computeExpensiveValue(a, b), [a, b]);`
Pasa una función de “crear” y un arreglo de dependencias. useMemo solo volverá a calcular el valor memorizado cuando una de las dependencias haya cambiado. Esta optimización ayuda a evitar cálculos costosos en cada render.
Recuerde que la función pasada a useMemo se ejecuta durante el renderizado. No hagas nada allí que normalmente no harías al renderizar. Por ejemplo, los efectos secundarios pertenecen a useEffect, no auseMemo.
> Escribe tu código para que aún funcione sin useMemo - y luego agrégalo para optimizar el rendimiento.
> React puede elegir “olvidar” algunos valores previamente memorizados y recalcularlos en el próximo renderizado, por ejemplo para liberar memoria
# Custom Hooks
### useAsync
```
import React, { useState, useEffect, useCallback } from "react";
// Usage
function App() {
const { execute, status, value, error } = useAsync(myFunction, false);
return (
<div>
{status === "idle" && <div>Start your journey by clicking a button</div>}
{status === "success" && <div>{value}</div>}
{status === "error" && <div>{error}</div>}
<button onClick={execute} disabled={status === "pending"}>
{status !== "pending" ? "Click me" : "Loading..."}
</button>
</div>
);
}
// An async function for testing our hook.
// Will be successful 50% of the time.
const myFunction = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
const rnd = Math.random() * 10;
rnd <= 5
? resolve("Submitted successfully 🙌")
: reject("Oh no there was an error 😞");
}, 2000);
});
};
// Hook
const useAsync = (asyncFunction, immediate = true) => {
const [status, setStatus] = useState("idle");
const [value, setValue] = useState(null);
const [error, setError] = useState(null);
const execute = useCallback(() => {
setStatus("pending");
setValue(null);
setError(null);
return asyncFunction()
.then((response) => {
setValue(response);
setStatus("success");
})
.catch((error) => {
setError(error);
setStatus("error");
});
}, [asyncFunction]);
// Call execute if we want to fire it right away.
// Otherwise execute can be called later, such as
// in an onClick handler.
useEffect(() => {
if (immediate) {
execute();
}
}, [execute, immediate]);
return { execute, status, value, error };
};
```
## Error boundary
Example
```
function FallBackError({ error }) {
return (
<div>
Something went wrong.
{error}
</div>
);
}
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
console.log(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return (
<this.props.FallBackError
error={this.state.hasError}
/>
);
}
return this.props.children;
}
}
```
App render
> Le colocamos una key, que es una manera de resetear cualquier componente, cambiando el valor de la key se resetea dicho componente.
```
<ErrorBoundary FallBackError={FallBackError} key={pokemonName}>
<PokemonInfo pokemonName={pokemonName} />
</ErrorBoundary>
```