Por 9.99€ al mes tendrás acceso completo a todos los cursos. Sin matrícula ni permanencia.
Un CustomHook es como un componente de React que en lugar de exportar jsx exporta funciones, estados, etc. Sería parecido a un fichero utils.js que en lugar de tener funciones puras de Javascript tiene funciones propias del ecosistema de React.
En todos los casos siguientes, la función calculateArea está definida dentro del propio Hook. Suele ser lo común, aunque también se podría calcular el resultado final directamente en el componente App.
Exportando cada hook por separado
use-rectangle.js
import { useState } from "react";
const useRectangle = (initialHeight, initialWidth) => {
const [width, setWidth] = useState(initialWidth);
const [height, setHeight] = useState(initialHeight);
const calculateArea = () => width * height;
const area = calculateArea();
return { width, height, setWidth, setHeight, area };
}
export default useRectangle;
App.js
import useRectangle from './use-rectangle';
function App() {
const { height, width, setWidth, setHeight, area } = useRectangle(0, 0);
return (
<div className="App">
<input type="text" placeholder="ancho" onChange={e => setWidth(e.target.value)} />
<input type="text" placeholder="alto" onChange={e => setHeight(e.target.value)} />
<output>
{area}
</output>
</div>
);
}
export default App;
Exportando todos los hooks en un solo objeto
App.js
import useRectangle from './use-rectangle';
function App() {
const [state, area, { updateState }] = useRectangle(0, 0);
return (
<div className="App">
<input type="text" placeholder="ancho" onChange={e => updateState('width', e.target.value)} />
<input type="text" placeholder="alto" onChange={e => updateState('height', e.target.value)} />
<output>
{area}
</output>
</div>
);
}
export default App;
use-rectangle.js
import { useState } from 'react';
const useRectangle = () => {
const [state, setState] = useState({ width: 0, height: 0, area: 0 });
const updateState = (prop, val) => {
const obj = { ...state, [prop]: val };
obj.area = obj.width * obj.height;
setState(obj);
}
return { state, updateState }
}
export default useRectangle
Usando useReducer
App.js
import useRectangle from './use-rectangle';
function App() {
const {state, updateState } = useRectangle();
return (
<div className="App">
<input type="text" placeholder="ancho" onChange={e => updateState('width', e.target.value)} />
<input type="text" placeholder="alto" onChange={e => updateState('height', e.target.value)} />
<output>
{state.area}
</output>
</div>
);
}
export default App;
use-rectangle.js
import { useReducer } from "react";
const calculatateArea = (opt) => {
const area = opt.width * opt.height;
return area;
};
// Patrón State Reducer
// El reducer es un método que modifica el estado a través de acciones
// el return del reducer será el nuevo estado
const reducer = (state, { prop, type, value }) => {
if (type === "update") {
const newState = {
...state,
[prop]: value,
};
return { ...newState, price: calculatateArea(newState) }
}
}
const useRectangle = () => {
// useReducer es un método que devuelve el estado y el dispatch, que es un método que utilizaremos para modificar el estado
const [state, dispatch] = useReducer(reducer, {
width: 0,
height: 0,
});
// El dispatch ejecutará automáticamente el reducer, pasándole el estado actual y los parámetros para modifcarlo
const updateState = (prop, value) => dispatch({
type: 'update',
prop,
value,
});
const area = calculatateArea(state);
return [state, { updateState }, area];
}
export default useRectangle;
Context API + useReducer vs Redux
Podríamos usar Context API y useReducer para obtener algo similar a lo que podemos hacer con Redux. Sin embargo, con Context API, todos los componentes serán renderizados de nuevo, mientras que con Redux sólo serán renderizados los componentes que lo necesiten, por tanto para proyectos que muestren muchos componentes Redux es más apropiado.