{"componentChunkName":"component---src-templates-content-template-js","path":"/es/part7/mas_sobre_los_hooks_de_react","result":{"data":{"markdownRemark":{"html":"<div class=\"content\">\n<p>Los ejercicios de esta parte del curso difieren un poco de los anteriores. Como de costumbre, hay algunos ejercicios relacionados con la teoría de este capítulo. Los demás capítulos de esta parte no tienen ejercicios separados.</p>\n<p>Además, esta parte contiene una serie más amplia de ejercicios que amplía la aplicación BlogList creada en las partes 4 y 5. Puedes encontrar esos ejercicios <a href=\"/es/part7/ejercicios_ampliar_la_lista_de_blogs\">aquí</a>.</p>\n<h3>Hooks de React</h3>\n<p>React ofrece 18 <a href=\"https://es.react.dev/reference/react/hooks\">hooks incorporados</a> diferentes, de los cuales los más populares son <a href=\"https://es.react.dev/reference/react/useState\">useState</a> y <a href=\"https://es.react.dev/reference/react/useEffect\">useEffect</a>, que ya hemos utilizado extensivamente.</p>\n<p>En la <a href=\"/es/part5/props_children_y_la_ref_del_componente#referencias-a-componentes-con-ref\">parte 5</a> usamos <a href=\"https://es.react.dev/reference/react/useRef\">useRef</a> y <a href=\"https://es.react.dev/reference/react/useImperativeHandle\">useImperativeHandle</a>, que permitieron que un componente proporcionara acceso a sus funciones a otros componentes. En la <a href=\"/es/part6/react_query_y_context_api\">parte 6</a> utilizamos <a href=\"https://es.react.dev/reference/react/useContext\">useContext</a> para implementar un estado global.</p>\n<p>En los últimos años, los hooks se han convertido en la forma estándar en que las librerías exponen sus APIs. A lo largo del curso ya hemos visto varios ejemplos: <a href=\"https://zustand-demo.pmnd.rs/\">Zustand</a> proporciona <i>useStore</i> para acceder al estado global, <a href=\"https://reactrouter.com/\">React Router</a> expone <i>useNavigate</i> y <i>useParams</i> para la navegación programática y el acceso a parámetros de la URL, y <a href=\"https://tanstack.com/query/latest\">React Query</a> ofrece <i>useQuery</i> y <i>useMutation</i> para gestionar el estado del servidor.</p>\n<p>Como se mencionó en la <a href=\"/es/part1/un_estado_mas_complejo_depurando_aplicaciones_react#reglas-de-los-hooks\">parte 1</a>, los hooks no son funciones normales y cuando los usamos tenemos que cumplir con ciertas <a href=\"https://es.react.dev/warnings/invalid-hook-call-warning#breaking-rules-of-hooks\">reglas o limitaciones</a>. Recapitulemos las reglas del uso de hooks, copiadas literalmente de la documentación oficial de React:</p>\n<p><strong>Evita utilizar Hooks dentro de loops, condicionales o funciones anidadas.</strong> En su lugar, utiliza los Hooks únicamente en el nivel superior de tu función de React.</p>\n<p><strong>Los Hooks sólo deben ser utilizados durante la renderización de un componente de función en React:</strong></p>\n<ul>\n<li>Utilízalos en el nivel superior del cuerpo de un componente de función.</li>\n<li>Utilízalos en el nivel superior del cuerpo de un Hook personalizado.</li>\n</ul>\n<p>Existe un <a href=\"https://www.npmjs.com/package/eslint-plugin-react-hooks\">plugin de ESLint</a> que se puede usar para verificar que la aplicación utiliza los hooks correctamente:</p>\n<picture><img src=\"/static/a42713feec07bc59d2ba81cbc95c239b/5a190/60ea.png\" alt=\"error de vscode al llamar a useState condicionalmente\" srcset=\"/static/a42713feec07bc59d2ba81cbc95c239b/772e8/60ea.png 200w,\n/static/a42713feec07bc59d2ba81cbc95c239b/e17e5/60ea.png 400w,\n/static/a42713feec07bc59d2ba81cbc95c239b/5a190/60ea.png 800w,\n/static/a42713feec07bc59d2ba81cbc95c239b/c1b63/60ea.png 1200w,\n/static/a42713feec07bc59d2ba81cbc95c239b/07a9c/60ea.png 1440w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Además de los hooks que ya hemos utilizado, React proporciona varios hooks incorporados que merece la pena conocer. En esta sección veremos dos de ellos, <i>useMemo</i> y <i>useCallback</i>, ambos relacionados con la optimización del rendimiento. Después pasaremos a los hooks personalizados, que permiten empaquetar cualquier combinación de hooks en una función reutilizable propia.</p>\n<h3>useMemo</h3>\n<p>Cada vez que un componente de React se vuelve a renderizar, se ejecuta de nuevo todo el cuerpo de la función. Para la mayoría de los componentes esto no supone ningún problema, pero en ocasiones un componente realiza un cálculo costoso —como filtrar una lista grande, ordenar datos u obtener un valor complejo— y repetirlo en cada renderizado desperdicia tiempo.</p>\n<p><a href=\"https://es.react.dev/reference/react/useMemo\">useMemo</a> permite almacenar en caché el resultado de un cálculo entre renderizados. Recibe una función que realiza el cálculo y un array de dependencias. React solo vuelve a ejecutar la función cuando cambia alguna de las dependencias; en caso contrario, devuelve el resultado almacenado anteriormente.</p>\n<p>Consideremos un componente que renderiza una larga lista de elementos filtrados por un término de búsqueda:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">expensiveCalculation</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">let</span> sum <span class=\"token operator\">=</span> <span class=\"token number\">0</span>\n  <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">let</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> <span class=\"token number\">100000</span><span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> sum <span class=\"token operator\">+=</span> i\n  <span class=\"token keyword\">return</span> sum\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token constant\">ITEMS</span> <span class=\"token operator\">=</span> Array<span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">length</span><span class=\"token operator\">:</span> <span class=\"token number\">10000</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">_<span class=\"token punctuation\">,</span> i</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">item </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>i <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">FilteredList</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>filter<span class=\"token punctuation\">,</span> setFilter<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>darkMode<span class=\"token punctuation\">,</span> setDarkMode<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'filtering...'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> filtered <span class=\"token operator\">=</span> <span class=\"token constant\">ITEMS</span><span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">expensiveCalculation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> item<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>filter<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div style<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">background</span><span class=\"token operator\">:</span> darkMode <span class=\"token operator\">?</span> <span class=\"token string\">'#333'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'#fff'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input\n        value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>filter<span class=\"token punctuation\">}</span>\n        onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token parameter\">e</span> <span class=\"token operator\">=></span> <span class=\"token function\">setFilter</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        placeholder<span class=\"token operator\">=</span><span class=\"token string\">\"filter items\"</span>\n      <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setDarkMode</span><span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>darkMode<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>toggle dark mode<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>filtered<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span> <span class=\"token operator\">=></span> <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>item<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> FilteredList</code></pre></div>\n<p>Filtrar la lista lleva ahora tiempo, en parte gracias a la ralentización artificial que hemos introducido.</p>\n<p>El problema del componente es que al hacer clic en el botón del modo oscuro se vuelven a filtrar los 10 000 elementos aunque el texto del filtro no haya cambiado.</p>\n<p>Podemos solucionarlo con <i>useMemo</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useMemo <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">FilteredList</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>filter<span class=\"token punctuation\">,</span> setFilter<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>darkMode<span class=\"token punctuation\">,</span> setDarkMode<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token boolean\">false</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> filtered <span class=\"token operator\">=</span> <span class=\"token function\">useMemo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'filtering...'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">return</span> <span class=\"token constant\">ITEMS</span><span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token function\">expensiveCalculation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">return</span> item<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span>filter<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>filter<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div style<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">background</span><span class=\"token operator\">:</span> darkMode <span class=\"token operator\">?</span> <span class=\"token string\">'#333'</span> <span class=\"token operator\">:</span> <span class=\"token string\">'#fff'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n      <span class=\"token comment\">//...</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Con <i>useMemo</i>, el filtrado costoso solo se ejecuta cuando cambia <i>filter</i>. Alternar el modo oscuro únicamente actualiza el color de fondo y la lista filtrada almacenada en caché se devuelve de inmediato.</p>\n<p>El array de dependencias funciona exactamente igual que el de <i>useEffect</i>: React compara cada valor con el del renderizado anterior. Si todos los valores son idénticos, se reutiliza el valor memorizado. Si alguno difiere, la función se ejecuta de nuevo y el resultado se almacena para el siguiente renderizado.</p>\n<p><i>useMemo</i> también puede utilizarse para memorizar objetos y arrays que se pasan como props, evitando renderizados innecesarios de componentes hijos que utilizan igualdad por referencia. Por ejemplo:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>filter<span class=\"token punctuation\">,</span> setFilter<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// Without useMemo, 'options' is a new object on every render even if filter hasn't changed</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> options <span class=\"token operator\">=</span> <span class=\"token function\">useMemo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">caseSensitive</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span> filter <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span>filter<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>SearchResults options<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>options<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p><i>useMemo</i> es una optimización del rendimiento; no deberías utilizarlo por defecto. La <a href=\"https://wiki.c2.com/?PrematureOptimization\">memorización prematura</a> añade complejidad sin aportar beneficios cuando el cálculo es rápido. Mide primero y añade <i>useMemo</i> solo cuando hayas confirmado que un cálculo concreto constituye un cuello de botella.</p>\n<h3>React.memo</h3>\n<p>Mientras que <i>useMemo</i> almacena en caché el resultado de un cálculo dentro de un componente, <a href=\"https://es.react.dev/reference/react/memo\">React.memo</a> adopta un enfoque diferente: almacena la salida renderizada de un componente completo. <i>React.memo</i> no es un hook, sino un componente de orden superior, y lo tratamos aquí porque complementa bien a <i>useMemo</i>. Cuando un componente está envuelto en <i>React.memo</i>, React omite su nuevo renderizado si sus props no han cambiado desde el renderizado anterior.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> MyComponent <span class=\"token operator\">=</span> React<span class=\"token punctuation\">.</span><span class=\"token function\">memo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> value <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'rendered'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>value<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Sin <i>React.memo</i>, <i>MyComponent</i> se vuelve a renderizar cada vez que lo hace su componente padre, aunque <i>value</i> sea el mismo. Con él, React compara las props anteriores y nuevas mediante una igualdad superficial y solo vuelve a renderizar cuando algo ha cambiado realmente.</p>\n<p>Ten en cuenta que <i>React.memo</i> solo comprueba las props. Si el componente utiliza un valor del contexto o su propio estado, seguirá renderizándose de nuevo cuando estos cambien.</p>\n<p><i>React.memo</i> se combina de forma natural con <i>useMemo</i>: <i>useMemo</i> evita que se repitan cálculos costosos, mientras que <i>React.memo</i> impide que el propio componente vuelva a renderizarse.</p>\n<p>Si un componente memorizado recibe una nueva referencia a una función u objeto en cada renderizado, la memorización queda anulada. Aquí es donde entra en juego <i>useCallback</i>.</p>\n<h3>useCallback</h3>\n<p>Las funciones definidas dentro de un componente se vuelven a crear como objetos nuevos en cada renderizado. Normalmente esto es inofensivo, pero se convierte en un problema en dos situaciones concretas:</p>\n<ul>\n<li>Un componente hijo envuelto en <a href=\"https://es.react.dev/reference/react/memo\">React.memo</a> recibe la función como prop. Como la función es un objeto nuevo cada vez, el hijo siempre detecta una prop distinta y se vuelve a renderizar, anulando el propósito de la memorización.</li>\n<li>Una función aparece como dependencia de <i>useEffect</i> o <i>useMemo</i>. Si se crea una función nueva en cada renderizado, el efecto o el valor memorizado se vuelven a ejecutar en cada renderizado.</li>\n</ul>\n<p><a href=\"https://es.react.dev/reference/react/useCallback\">useCallback</a> resuelve este problema almacenando en caché la propia función entre renderizados y devolviendo el mismo objeto función mientras no cambien sus dependencias. Recibe una función y un array de dependencias, con una estructura idéntica a la de <i>useMemo</i>.</p>\n<p>Veamos un ejemplo concreto. Tenemos un componente <i>NoteList</i> costoso de renderizar, así que lo envolvemos en <i>React.memo</i>:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// React.memo makes this component skip re-rendering if its props haven't changed</span>\n<span class=\"token keyword\">const</span> NoteList <span class=\"token operator\">=</span> <span class=\"token function\">memo</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> onDelete<span class=\"token punctuation\">,</span> notes <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'NoteList rendered'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>ul<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span>\n        <span class=\"token operator\">&lt;</span>li key<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n          <span class=\"token punctuation\">{</span>note<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">}</span>\n          <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">onDelete</span><span class=\"token punctuation\">(</span>note<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token keyword\">delete</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>li<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ul<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>notes<span class=\"token punctuation\">,</span> setNotes<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Learn React'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Learn hooks'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Learn useMemo'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">4</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Learn useCallback'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> <span class=\"token number\">5</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token string\">'Build something cool'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>newNote<span class=\"token punctuation\">,</span> setNewNote<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleDelete</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">notes</span> <span class=\"token operator\">=></span> notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleAdd</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">notes</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">[</span><span class=\"token operator\">...</span>notes<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">id</span><span class=\"token operator\">:</span> Date<span class=\"token punctuation\">.</span><span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> newNote <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">setNewNote</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>newNote<span class=\"token punctuation\">}</span> onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token parameter\">e</span> <span class=\"token operator\">=></span> <span class=\"token function\">setNewNote</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleAdd<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>add<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>NoteList notes<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>notes<span class=\"token punctuation\">}</span> onDelete<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>handleDelete<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>El problema es que <i>handleDelete</i> está definida como una función normal dentro de <i>App</i>. Cada vez que <i>App</i> se vuelve a renderizar —lo que ocurre con cada pulsación en el campo de la nueva nota— se crea un objeto función completamente nuevo y se pasa a <i>NoteList</i> como prop <i>onDelete</i>.</p>\n<p>Desde la perspectiva de <i>React.memo</i>, la prop ha cambiado, por lo que <i>NoteList</i> vuelve a renderizarse aunque la lista no haya cambiado:</p>\n<picture><img src=\"/static/a1db90da01dad5ac2b87581c3800af1d/5a190/h1.png\" alt=\"muchos renderizados repetidos\" srcset=\"/static/a1db90da01dad5ac2b87581c3800af1d/772e8/h1.png 200w,\n/static/a1db90da01dad5ac2b87581c3800af1d/e17e5/h1.png 400w,\n/static/a1db90da01dad5ac2b87581c3800af1d/5a190/h1.png 800w,\n/static/a1db90da01dad5ac2b87581c3800af1d/c1b63/h1.png 1200w,\n/static/a1db90da01dad5ac2b87581c3800af1d/29007/h1.png 1600w,\n/static/a1db90da01dad5ac2b87581c3800af1d/6a5c3/h1.png 1646w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Podemos solucionarlo con <i>useCallback</i>, que devuelve el mismo objeto función entre renderizados mientras sus dependencias no cambien:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useCallback<span class=\"token punctuation\">,</span> memo <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>notes<span class=\"token punctuation\">,</span> setNotes<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>newNote<span class=\"token punctuation\">,</span> setNewNote<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> handleDelete <span class=\"token operator\">=</span> <span class=\"token function\">useCallback</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">id</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">    <span class=\"token function\">setNotes</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">notes</span> <span class=\"token operator\">=></span> notes<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">note</span> <span class=\"token operator\">=></span> note<span class=\"token punctuation\">.</span>id <span class=\"token operator\">!==</span> id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></span><span class=\"gatsby-highlight-code-line\">  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// no external dependencies: this function never needs to change</span></span>\n  <span class=\"token comment\">// ...</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token comment\">// ...</span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Ahora <i>handleDelete</i> es estable: React devuelve exactamente el mismo objeto función en cada renderizado, por lo que <i>React.memo</i> no detecta ningún cambio en la prop <i>onDelete</i> y omite por completo el nuevo renderizado de <i>NoteList</i>.</p>\n<p>Al igual que <i>useMemo</i>, utiliza <i>useCallback</i> solo cuando tengas un problema concreto, como un componente hijo memorizado que se renderiza innecesariamente o un <i>useEffect</i> que se ejecuta con demasiada frecuencia debido a una dependencia de función. Añadirlo en todas partes hace que el código sea más difícil de leer sin aportar ninguna mejora de rendimiento.</p>\n<h3>Hooks personalizados</h3>\n<p>React ofrece la opción de crear nuestros propios hooks <a href=\"https://es.react.dev/learn/reusing-logic-with-custom-hooks\">personalizados</a>. Según React, el propósito principal de los hooks personalizados es facilitar la reutilización de la lógica utilizada en los componentes.</p>\n<blockquote>\n<p><i>Crear tus propios Hooks te permite extraer la lógica de los componentes en funciones reutilizables.</i></p>\n</blockquote>\n<p>Los hooks personalizados son funciones normales de JavaScript que pueden utilizar cualquier otro hook, siempre que respeten las <a href=\"/es/part1/un_estado_mas_complejo_depurando_aplicaciones_react#reglas-de-los-hooks\">reglas de los hooks</a>. Además, el nombre de los hooks personalizados debe comenzar con la palabra <i>use</i>.</p>\n<p>La idea clave es que cualquier lógica con estado que te encuentres duplicando entre componentes es candidata a extraerse a un hook personalizado. Cada llamada al mismo hook crea una porción de estado independiente. Esto es lo que distingue un hook personalizado de una función de utilidad corriente.</p>\n<p>Ya hemos implementado varios hooks personalizados en la parte 6. Los hooks <i>useNotes</i> y <i>useNoteActions</i> se crearon en la sección sobre <a href=\"/es/part6/arquitectura_flux_y_zustand#notas-de-zustand\">Zustand</a>, y <i>useCounter</i> se definió en la sección sobre <a href=\"/es/part6/react_query_y_context_api#definir-el-contexto-del-contador-en-su-propio-archivo\">React Query y Context</a>.</p>\n<h4>Hook de contador</h4>\n<p>Implementamos una aplicación de contador en la <a href=\"/es/part1/estado_del_componente_controladores_de_eventos#control-de-eventos\">parte 1</a>, que puede tener su valor incrementado, reducido o reiniciado. El código de la aplicación es el siguiente:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>counter<span class=\"token punctuation\">,</span> setCounter<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCounter</span><span class=\"token punctuation\">(</span>counter <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        plus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCounter</span><span class=\"token punctuation\">(</span>counter <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        minus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>      \n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCounter</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        zero\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Extraigamos la lógica del contador en su propio hook personalizado. El código del hook es el siguiente:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useCounter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>value<span class=\"token punctuation\">,</span> setValue<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">increase</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span>value <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">decrease</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span>value <span class=\"token operator\">-</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">zero</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    value<span class=\"token punctuation\">,</span> \n    increase<span class=\"token punctuation\">,</span>\n    decrease<span class=\"token punctuation\">,</span>\n    zero\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Nuestro hook personalizado utiliza el hook <em>useState</em> internamente para crear su propio estado. El hook devuelve un objeto, cuyas propiedades incluyen el valor del contador, así como funciones para manipular el valor.</p>\n<p>Los componentes de React pueden utilizar el hook como se muestra a continuación:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> counter <span class=\"token operator\">=</span> <span class=\"token function\">useCounter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">.</span>increase<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        plus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">.</span>decrease<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        minus\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>      \n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>counter<span class=\"token punctuation\">.</span>zero<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        zero\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Al hacer esto, podemos extraer el estado del componente <em>App</em> y su manipulación por completo en el hook <em>useCounter</em>. La gestión del estado y la lógica del contador ahora es responsabilidad del hook personalizado.</p>\n<p>El mismo hook podría <i>reutilizarse</i> en la aplicación que realizaba un seguimiento de la cantidad de clics realizados en los botones izquierdo y derecho:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> left <span class=\"token operator\">=</span> <span class=\"token function\">useCounter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> right <span class=\"token operator\">=</span> <span class=\"token function\">useCounter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>left<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>left<span class=\"token punctuation\">.</span>increase<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        left\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>button onClick<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>right<span class=\"token punctuation\">.</span>increase<span class=\"token punctuation\">}</span><span class=\"token operator\">></span>\n        right\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>button<span class=\"token operator\">></span>\n      <span class=\"token punctuation\">{</span>right<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>La aplicación crea <i>dos</i> contadores completamente separados. El primero se asigna a la variable <i>left</i> y el otro a la variable <i>right</i>. Cada llamada a <i>useCounter</i> crea su propia porción de estado independiente.</p>\n<h4>Hooks personalizados y nuevos renderizados de componentes</h4>\n<p>Una pregunta natural en este punto es: ¿cuándo se vuelve a renderizar realmente un componente que utiliza un hook personalizado?</p>\n<p>La respuesta es sencilla cuando se entiende qué es en realidad un hook personalizado. Desde la perspectiva del componente, un hook personalizado no es una entidad separada. Es simplemente una parte de la lógica del propio componente que se ha trasladado a una función independiente. Esto significa que todo el estado y los efectos definidos dentro del hook pertenecen al componente que lo llama, no al propio hook.</p>\n<p>En consecuencia, las reglas de renderizado son exactamente las mismas que con los hooks incorporados. El componente vuelve a renderizarse cuando cambia un estado gestionado dentro del hook, cuando cambia un valor de contexto al que el hook está suscrito o cuando cualquier hook al que el hook personalizado llama internamente provoca un nuevo renderizado.</p>\n<p>En cambio, acciones como reasignar variables normales dentro del hook o que cambien por sí solos los argumentos pasados al hook no provocan un nuevo renderizado.</p>\n<p>Los argumentos merecen un análisis más detallado. Pasar un nuevo valor a un hook no programa por sí mismo un nuevo renderizado, pero si el hook utiliza ese argumento como dependencia de un <i>useEffect</i> o un <i>useMemo</i>, el cambio hará que el efecto o el valor memorizado vuelvan a ejecutarse. Si esto, a su vez, llama a una función actualizadora del estado, el componente se renderizará de nuevo.</p>\n<p>Una forma útil de entenderlo es imaginar que copias y pegas todo el código del hook personalizado directamente dentro del componente. El comportamiento de renderizado sería idéntico. El hook solo sirve para organizar ese código; no es un límite que React trate de una manera especial.</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useCounter</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>count<span class=\"token punctuation\">,</span> setCount<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// this state belongs to the calling component</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span> count<span class=\"token punctuation\">,</span> <span class=\"token function-variable function\">increment</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setCount</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">c</span> <span class=\"token operator\">=></span> c <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">MyComponent</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> count<span class=\"token punctuation\">,</span> increment <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useCounter</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">// re-renders whenever the count state inside the hook is updated</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h4>Hook para campos de formulario</h4>\n<p>Tratar con formularios en React es algo complicado. La siguiente aplicación presenta al usuario un formulario que le solicita que ingrese su nombre, fecha de nacimiento y altura:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>name<span class=\"token punctuation\">,</span> setName<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>born<span class=\"token punctuation\">,</span> setBorn<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>height<span class=\"token punctuation\">,</span> setHeight<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>form<span class=\"token operator\">></span>\n        <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> \n        <span class=\"token operator\">&lt;</span>input\n          type<span class=\"token operator\">=</span><span class=\"token string\">'text'</span>\n          value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">}</span>\n          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setName</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span> \n        <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token operator\">&lt;</span>br<span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token literal-property property\">birthdate</span><span class=\"token operator\">:</span>\n        <span class=\"token operator\">&lt;</span>input\n          type<span class=\"token operator\">=</span><span class=\"token string\">'date'</span>\n          value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>born<span class=\"token punctuation\">}</span>\n          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setBorn</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token literal-property property\">height</span><span class=\"token operator\">:</span>\n        <span class=\"token operator\">&lt;</span>input\n          type<span class=\"token operator\">=</span><span class=\"token string\">'number'</span>\n          value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>height<span class=\"token punctuation\">}</span>\n          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token function\">setHeight</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span>\n        <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>born<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>height<span class=\"token punctuation\">}</span> \n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Cada campo del formulario tiene su propio estado. Para mantener el estado del formulario sincronizado con los datos proporcionados por el usuario, tenemos que registrar un controlador <i>onChange</i> apropiado para cada uno de los elementos <i>input</i>. El patrón es idéntico para todos los campos; solo cambia el nombre de la variable de estado. Este es exactamente el tipo de repetición que los hooks personalizados están diseñados para eliminar.</p>\n<p>Definamos nuestro propio hook personalizado <em>useField</em>, que simplifica la gestión del estado del formulario:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useField</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">type</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>value<span class=\"token punctuation\">,</span> setValue<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">onChange</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    type<span class=\"token punctuation\">,</span>\n    value<span class=\"token punctuation\">,</span>\n    onChange\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>La función de hook recibe el tipo de campo de entrada como parámetro. Devuelve todos los atributos requeridos por el <i>input</i>: su tipo, valor y el controlador onChange.</p>\n<p>El hook se puede utilizar de la siguiente manera:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> name <span class=\"token operator\">=</span> <span class=\"token function\">useField</span><span class=\"token punctuation\">(</span><span class=\"token string\">'text'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">// ...</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>form<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>input\n          type<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">}</span>\n          value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span>\n          onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">.</span>onChange<span class=\"token punctuation\">}</span> \n        <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token comment\">// ...</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n<span class=\"token comment\">// ...</span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">        <span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>born<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>height<span class=\"token punctuation\">}</span></span>      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>      \n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h3>Propagación de atributos con spread</h3>\n<p>Podríamos simplificar un poco más las cosas. Dado que el objeto <em>name</em> tiene exactamente todos los atributos que el elemento <i>input</i> espera recibir como props, podemos pasar los props al elemento usando la <a href=\"https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Operators/Spread_syntax\">sintaxis spread</a>(spread syntax) de la siguiente manera:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>input <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>name<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span> </code></pre></div>\n<p>Como indica el <a href=\"https://es.react.dev/learn/updating-objects-in-state#copying-objects-with-the-spread-syntax\">ejemplo</a> en la documentación de React, las siguientes dos formas de pasar props a un componente logran exactamente el mismo resultado:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>Greeting firstName<span class=\"token operator\">=</span><span class=\"token string\">'Arto'</span> lastName<span class=\"token operator\">=</span><span class=\"token string\">'Hellas'</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n\n<span class=\"token keyword\">const</span> person <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">firstName</span><span class=\"token operator\">:</span> <span class=\"token string\">'Arto'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">lastName</span><span class=\"token operator\">:</span> <span class=\"token string\">'Hellas'</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token operator\">&lt;</span>Greeting <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>person<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span></code></pre></div>\n<p>La aplicación se simplifica en el siguiente formato:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> name <span class=\"token operator\">=</span> <span class=\"token function\">useField</span><span class=\"token punctuation\">(</span><span class=\"token string\">'text'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> born <span class=\"token operator\">=</span> <span class=\"token function\">useField</span><span class=\"token punctuation\">(</span><span class=\"token string\">'date'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">const</span> height <span class=\"token operator\">=</span> <span class=\"token function\">useField</span><span class=\"token punctuation\">(</span><span class=\"token string\">'number'</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>form<span class=\"token operator\">></span>\n        <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> \n        <span class=\"token operator\">&lt;</span>input  <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>name<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token operator\">&lt;</span>br<span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token literal-property property\">birthdate</span><span class=\"token operator\">:</span>\n        <span class=\"token operator\">&lt;</span>input <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>born<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>br <span class=\"token operator\">/</span><span class=\"token operator\">></span> \n        <span class=\"token literal-property property\">height</span><span class=\"token operator\">:</span>\n        <span class=\"token operator\">&lt;</span>input <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>height<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>form<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>born<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span> <span class=\"token punctuation\">{</span>height<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Tratar con formularios se simplifica enormemente cuando los desagradables detalles esenciales relacionados con la sincronización del estado del formulario se encapsulan dentro de nuestro hook personalizado.</p>\n<h4>Persistencia del estado con un hook personalizado</h4>\n<p>Los hooks personalizados pueden combinar varios hooks incorporados para encapsular comportamientos más complejos. Una funcionalidad que se necesita habitualmente es persistir el estado en <i>localStorage</i> para que sobreviva a una recarga de la página. El siguiente hook <i>useLocalStorage</i> envuelve <i>useState</i> y mantiene el valor sincronizado con localStorage:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useLocalStorage</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">key<span class=\"token punctuation\">,</span> initialValue</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>storedValue<span class=\"token punctuation\">,</span> setStoredValue<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">const</span> item <span class=\"token operator\">=</span> window<span class=\"token punctuation\">.</span>localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">getItem</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">)</span>\n      <span class=\"token keyword\">return</span> item <span class=\"token operator\">?</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">)</span> <span class=\"token operator\">:</span> initialValue\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> initialValue\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">setValue</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">value</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">try</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token function\">setStoredValue</span><span class=\"token punctuation\">(</span>value<span class=\"token punctuation\">)</span>\n      window<span class=\"token punctuation\">.</span>localStorage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span>key<span class=\"token punctuation\">,</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span> <span class=\"token keyword\">catch</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">[</span>storedValue<span class=\"token punctuation\">,</span> setValue<span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>El hook recibe una clave de almacenamiento y un valor inicial. En el primer renderizado lee el valor de localStorage y recurre a <i>initialValue</i> si todavía no hay nada almacenado. La función actualizadora que devuelve modifica al mismo tiempo tanto el estado de React como localStorage.</p>\n<p>Un componente que lo utiliza tiene exactamente el mismo aspecto que uno que emplea <i>useState</i> directamente:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>name<span class=\"token punctuation\">,</span> setName<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useLocalStorage</span><span class=\"token punctuation\">(</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>input value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">}</span> onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token parameter\">e</span> <span class=\"token operator\">=></span> <span class=\"token function\">setName</span><span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>p<span class=\"token operator\">></span>Hello<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>name<span class=\"token punctuation\">}</span><span class=\"token operator\">!</span> <span class=\"token punctuation\">(</span>your name is stored <span class=\"token keyword\">in</span> localStorage<span class=\"token punctuation\">)</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>p<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>El componente no sabe que localStorage está implicado. Esa responsabilidad queda completamente oculta dentro del hook.</p>\n<h3>Más sobre hooks</h3>\n<p>Los hooks personalizados no son solo una herramienta para reutilizar código; también proporcionan una forma mejor de dividirlo en partes modulares más pequeñas.</p>\n<p>Internet está comenzando a llenarse con más y más material útil relacionado con los hooks. Vale la pena consultar las siguientes fuentes:</p>\n<ul>\n<li><a href=\"https://github.com/rehooks/awesome-react-hooks\">Awesome React Hooks Resources</a></li>\n<li><a href=\"https://usehooks.com/\">Easy to understand React Hook recipes by Gabe Ragland</a></li>\n</ul>\n</div>\n<div class=\"tasks\">\n<h3>Ejercicios 7.1.-7.6.</h3>\n<p>Volvamos una vez más a trabajar con anécdotas. Utiliza como punto de partida para los ejercicios la aplicación del repositorio <a href=\"https://github.com/fullstack-hy2020/routed-anecdotes\">https://github.com/fullstack-hy2020/routed-anecdotes</a>.</p>\n<p>Si clonas el proyecto dentro de un repositorio de Git existente, recuerda eliminar la configuración de Git de la aplicación clonada:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> routed-anecdotes   // go first to directory of the cloned repository\n<span class=\"token function\">rm</span> <span class=\"token parameter variable\">-rf</span> .git</code></pre></div>\n<p>La aplicación se inicia de la forma habitual, pero antes debes instalar sus dependencias:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span>\n<span class=\"token function\">npm</span> run dev</code></pre></div>\n<h4>7.1: Hook useField</h4>\n<p>Copia el hook personalizado <i>useField</i> en el archivo <i>src/hooks/index.js</i>. El hook debe gestionar el estado de un único campo de formulario y devolver un objeto con las siguientes propiedades: <i>type</i>, <i>value</i> y <i>onChange</i>.</p>\n<p>Si utilizas la <a href=\"https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/export#descripci%C3%B3n\">exportación nombrada</a> en lugar de la exportación predeterminada:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useField</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">type</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>value<span class=\"token punctuation\">,</span> setValue<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token string\">''</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">onChange</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">setValue</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>target<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">{</span>\n    type<span class=\"token punctuation\">,</span>\n    value<span class=\"token punctuation\">,</span>\n    onChange\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// modules can have several named exports</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">useAnotherHook</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span></span>  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Luego, la <a href=\"https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Statements/import\">importación</a> ocurre de la siguiente manera:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span>  <span class=\"token punctuation\">{</span> useField <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./hooks'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// ...</span>\n  <span class=\"token keyword\">const</span> username <span class=\"token operator\">=</span> <span class=\"token function\">useField</span><span class=\"token punctuation\">(</span><span class=\"token string\">'text'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Utiliza el hook en el formulario de creación de anécdotas.</p>\n<h4>7.2: useField con reset</h4>\n<p>Añade al formulario un botón que borre todos los campos de entrada:</p>\n<picture><img src=\"/static/3eb83473dbdad45d819367b8bdc6a06d/5a190/e2.png\" alt=\"formulario de anécdotas con botón reset\" srcset=\"/static/3eb83473dbdad45d819367b8bdc6a06d/772e8/e2.png 200w,\n/static/3eb83473dbdad45d819367b8bdc6a06d/e17e5/e2.png 400w,\n/static/3eb83473dbdad45d819367b8bdc6a06d/5a190/e2.png 800w,\n/static/3eb83473dbdad45d819367b8bdc6a06d/c1b63/e2.png 1200w,\n/static/3eb83473dbdad45d819367b8bdc6a06d/2215f/e2.png 1548w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Amplía el hook <i>useField</i> para que exponga una función <i>reset</i> que borre el valor del campo.</p>\n<p>Dependiendo de tu solución, es posible que veas la siguiente advertencia en tu consola:</p>\n<picture><img src=\"/static/c4f6d266117f4d881d1df60a4ca3b9f5/5a190/62ea.png\" alt=\"consola con advertencia: valor invalido para prop reset\" srcset=\"/static/c4f6d266117f4d881d1df60a4ca3b9f5/772e8/62ea.png 200w,\n/static/c4f6d266117f4d881d1df60a4ca3b9f5/e17e5/62ea.png 400w,\n/static/c4f6d266117f4d881d1df60a4ca3b9f5/5a190/62ea.png 800w,\n/static/c4f6d266117f4d881d1df60a4ca3b9f5/c1b63/62ea.png 1200w,\n/static/c4f6d266117f4d881d1df60a4ca3b9f5/29007/62ea.png 1600w,\n/static/c4f6d266117f4d881d1df60a4ca3b9f5/b4904/62ea.png 1768w\" sizes=\"(max-width: 800px) 100vw, 800px\"></picture>\n<p>Volveremos a esta advertencia en el próximo ejercicio.</p>\n<h4>7.3: Corrección del problema con spread</h4>\n<p>Si tu solución no provocó que apareciera una advertencia en la consola, ya has terminado este ejercicio.</p>\n<p>Si ves la advertencia <i>Invalid value for prop `reset` on &#x3C;input> tag</i> en la consola, realiza los cambios necesarios para eliminarla.</p>\n<p>El motivo de esta advertencia es que después de realizar los cambios en tu aplicación, la siguiente expresión:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>input <span class=\"token punctuation\">{</span><span class=\"token operator\">...</span>content<span class=\"token punctuation\">}</span><span class=\"token operator\">/</span><span class=\"token operator\">></span></code></pre></div>\n<p>Esencialmente, es lo mismo que esto:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>input\n  value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>content<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span> \n  type<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>content<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">}</span>\n  onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>content<span class=\"token punctuation\">.</span>onChange<span class=\"token punctuation\">}</span>\n<span class=\"gatsby-highlight-code-line\">  reset<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>content<span class=\"token punctuation\">.</span>reset<span class=\"token punctuation\">}</span></span><span class=\"token operator\">/</span><span class=\"token operator\">></span></code></pre></div>\n<p>El elemento <i>input</i> no debe recibir un atributo <i>reset</i>.</p>\n<p>Una solución simple sería no usar la sintaxis de spread y escribir todos los formularios de esta manera:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token operator\">&lt;</span>input\n  value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>username<span class=\"token punctuation\">.</span>value<span class=\"token punctuation\">}</span> \n  type<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>username<span class=\"token punctuation\">.</span>type<span class=\"token punctuation\">}</span>\n  onChange<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>username<span class=\"token punctuation\">.</span>onChange<span class=\"token punctuation\">}</span>\n<span class=\"token operator\">/</span><span class=\"token operator\">></span></code></pre></div>\n<p>Si hiciéramos esto, perderíamos gran parte del beneficio proporcionado por el hook <i>useField</i>. En su lugar, busca una solución al problema, pero que aún sea fácil de usar con la sintaxis de spread.</p>\n<h4>7.4: useAnecdotes, paso 1</h4>\n<p>El proyecto ya tiene configurado un servidor JSON. Puedes iniciarlo con:</p>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> run server</code></pre></div>\n<p>Esto inicia un backend de JSON Server que expone la colección de anécdotas como un recurso REST en <i><a href=\"http://localhost:3001/anecdotes\">http://localhost:3001/anecdotes</a></i>.</p>\n<p>El archivo existente <i>services/anecdotes.js</i> contiene las funciones necesarias para comunicarse con el backend, excepto la del último ejercicio. Ten en cuenta que el servicio utiliza la <a href=\"https://developer.mozilla.org/es/docs/Web/API/Fetch_API\">Fetch API</a> en vez de Axios para las peticiones HTTP. Si no conoces Fetch, consulta la <a href=\"/es/part6/estado_complejo_fetch_y_pruebas#fetch-api\">parte 6</a> antes de continuar.</p>\n<p>El patrón habitual para obtener datos de un servidor en React tiene este aspecto:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useState<span class=\"token punctuation\">,</span> useEffect <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'react'</span>\n<span class=\"token keyword\">import</span> anecdoteService <span class=\"token keyword\">from</span> <span class=\"token string\">'./services/anecdotes'</span>\n\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">[</span>anecdotes<span class=\"token punctuation\">,</span> setAnecdotes<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token function\">useState</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token function\">useEffect</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    anecdoteService<span class=\"token punctuation\">.</span><span class=\"token function\">getAll</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">data</span> <span class=\"token operator\">=></span> <span class=\"token function\">setAnecdotes</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Implementa un hook personalizado <i>useAnecdotes</i> que encapsule esta comunicación con el servidor. Para este ejercicio basta con que el hook obtenga todas las anécdotas. La creación de nuevas anécdotas puede abordarse en el siguiente ejercicio.</p>\n<p>El hook debe utilizarse de esta forma:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token comment\">// ...</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useAnecdotes <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'./hooks'</span></span>\n<span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n<span class=\"gatsby-highlight-code-line\">  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> anecdotes <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useAnecdotes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></span>\n  <span class=\"token keyword\">const</span> <span class=\"token function-variable function\">addAnecdote</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span> <span class=\"token comment\">// a dummy function to keep code from breaking</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Router<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span>Software anecdotes<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Menu <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Routes<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>AnecdoteList anecdotes<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>anecdotes<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/create\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>CreateNew addAnecdote<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span>addAnecdote<span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/about\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>About <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Routes<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Footer <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Router<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> App</code></pre></div>\n<p><strong>Una pista:</strong> antes se mencionó lo siguiente:</p>\n<blockquote>\n<p>Una forma útil de entenderlo —es decir, de entender cómo funciona un hook— es imaginar que copias y pegas todo el código del hook personalizado directamente dentro del componente.</p>\n</blockquote>\n<p>Ahora debes hacer, en cierto modo, lo contrario: copiar y pegar el código pertinente del componente en el hook. Esto incluye tanto <i>useState</i> como <i>useEffect</i>.</p>\n<h4>7.5: useAnecdotes, paso 2</h4>\n<p>Amplía el hook <i>useAnecdotes</i> para que también permita crear nuevas anécdotas. El hook debe exponer una función <i>addAnecdote</i> que envíe la nueva anécdota al servidor y actualice el estado local.</p>\n<p>Ahora el hook debe poder utilizarse así:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> anecdotes<span class=\"token punctuation\">,</span> addAnecdote <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useAnecdotes</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>Actualiza el componente <i>App</i> para pasar <i>addAnecdote</i> al componente <i>CreateNew</i> en lugar de la función provisional.</p>\n<h4>7.6: useAnecdotes, paso 3</h4>\n<p>Amplía el hook <i>useAnecdotes</i> con una función <i>deleteAnecdote</i> que elimine una anécdota del servidor y actualice el estado local. Añade un botón para eliminar junto a cada anécdota de la lista.</p>\n<p>Además, refactoriza la aplicación para que ni los datos de las anécdotas ni las funciones del hook se pasen como props. En su lugar, los componentes que los necesiten deben llamar directamente a <i>useAnecdotes</i>. Esto significa que <i>App</i> ya no tiene que actuar como intermediario pasando datos y callbacks por el árbol de componentes.</p>\n<p>Tras la refactorización, <i>App</i> debe tener este aspecto:</p>\n<div class=\"gatsby-highlight\" data-language=\"js\"><pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">App</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token operator\">&lt;</span>Router<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span>div<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>h1<span class=\"token operator\">></span>Software anecdotes<span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>h1<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Menu <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Routes<span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>AnecdoteList <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/create\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>CreateNew <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>Route path<span class=\"token operator\">=</span><span class=\"token string\">\"/about\"</span> element<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token operator\">&lt;</span>About <span class=\"token operator\">/</span><span class=\"token operator\">></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Routes<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>Footer <span class=\"token operator\">/</span><span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>div<span class=\"token operator\">></span>\n    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Router<span class=\"token operator\">></span>\n  <span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n</div>","frontmatter":{"mainImage":{"publicURL":"/static/2184b1c35920cfc7a09e10660dea04eb/part-7.svg"},"part":7,"letter":"a","lang":"es"}}},"pageContext":{"part":7,"letter":"a","lang":"es"}},"staticQueryHashes":["3128451518"]}