diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 5d9554a1a..a4a767dbc 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -1,37 +1,37 @@ --- -title: 'Lifecycle of Reactive Effects' +title: 'Ciclo de vida de los Efectos reactivos' --- -Effects have a different lifecycle from components. Components may mount, update, or unmount. An Effect can only do two things: to start synchronizing something, and later to stop synchronizing it. This cycle can happen multiple times if your Effect depends on props and state that change over time. React provides a linter rule to check that you've specified your Effect's dependencies correctly. This keeps your Effect synchronized to the latest props and state. +Los Efectos tienen un diferente ciclo de vida al de los componentes. Los componentes pueden montarse, actualizarse o desmontarse. Un Efecto solo puede hacer dos cosas: empezar a sincronizar algo y luego dejar de sincronizarlo. Este ciclo puede suceder varias veces si tu Efecto depende de props y estado que cambian con el tiempo. React provee una regla del _linter_ para comprobar que hayas especificado las dependencias de tu Efecto correctamente. Esto mantiene tu Efecto sincronizado con las últimas props y estado. -- How an Effect's lifecycle is different from a component's lifecycle -- How to think about each individual Effect in isolation -- When your Effect needs to re-synchronize, and why -- How your Effect's dependencies are determined -- What it means for a value to be reactive -- What an empty dependency array means -- How React verifies your dependencies are correct with a linter -- What to do when you disagree with the linter +- Cómo un ciclo de vida de un Efecto es diferente del ciclo de vida de un componente +- Cómo pensar en cada Efecto de forma aislada +- Cuándo tu Efecto necesita volver a sincronizarse, y por qué +- Cómo se determinan las dependencias de tu Efecto +- Qué significa para un valor ser reactivo +- Qué significa un _array_ de dependencias vacío +- Cómo React verifica con un _linter_ que tus dependencias son correctas +- Qué hacer cuanto no estás de acuerdo con el _linter_ -## The lifecycle of an Effect {/*the-lifecycle-of-an-effect*/} +## El ciclo de vida de un Efecto {/*the-lifecycle-of-an-effect*/} -Every React component goes through the same lifecycle: +Cada componente de React pasa por el mismo ciclo de vida: -- A component _mounts_ when it's added to the screen. -- A component _updates_ when it receives new props or state, usually in response to an interaction. -- A component _unmounts_ when it's removed from the screen. +- Un componente se _monta_ cuando es agregado a la pantalla. +- Un componente se _actualiza_ cuando recibe nuevas props o estado, por lo general en respuesta de una interacción. +- Un componente se _desmonta_ cuando es removido de la pantalla. -**It's a good way to think about components, but _not_ about Effects.** Instead, try to think about each Effect independently from your component's lifecycle. An Effect describes how to [synchronize an external system](/learn/synchronizing-with-effects) to the current props and state. As your code changes, synchronization will need to happen more or less often. +**Es una buena manera de pensar sobre los componentes, pero _no_ sobre los Efectos.** En cambio, intenta pensar en cada Efecto independientemente del ciclo de vida de tu componente. Un Efecto describe cómo [sincronizar un sistema externo](/learn/synchronizing-with-effects) con las props actuales y el estado. A medida que tu código cambia, la sincronización tendrá que suceder más o menos a menudo. -To illustrate this point, consider this Effect connecting your component to a chat server: +Para ilustrar este punto, considera este Efecto que conecta tu componente a un servidor de chat: ```js const serverUrl = 'https://localhost:1234'; @@ -48,7 +48,7 @@ function ChatRoom({ roomId }) { } ``` -Your Effect's body specifies how to **start synchronizing:** +El cuerpo de tu Efecto especifica cómo **iniciar la sincronización:** ```js {2-3} // ... @@ -60,7 +60,7 @@ Your Effect's body specifies how to **start synchronizing:** // ... ``` -The cleanup function returned by your Effect specifies how to **stop synchronizing:** +La función de limpieza devuelta por tu Efecto especifica cómo **detener la sincronización:** ```js {5} // ... @@ -72,141 +72,141 @@ The cleanup function returned by your Effect specifies how to **stop synchronizi // ... ``` -Intuitively, you might think that React would **start synchronizing** when your component mounts and **stop synchronizing** when your component unmounts. However, this is not the end of the story! Sometimes, it may also be necessary to **start and stop synchronizing multiple times** while the component remains mounted. +Intuitivamente, podrías pensar que React empezaría a sincronizarse cuando el componente se monta y dejaría de sincronizarse cuando el componente se desmonta. Sin embargo, ¡Este no es el final de la historia! A veces, también puede ser necesario **iniciar y detener la sincronización varias veces** mientras el componente permanece montado. -Let's look at _why_ this is necessary, _when_ it happens, and _how_ you can control this behavior. +Veamos _por qué_ esto es necesario, _cuándo_ sucede, y _cómo_ se puede controlar este comportamiento. -Some Effects don't return a cleanup function at all. [More often than not,](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) you'll want to return one--but if you don't, React will behave as if you returned an empty cleanup function. +Algunos Efectos no devuelven una función de limpieza en absoluto. [Más a menudo que no,](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) tu querrás devolver uno, pero si no, React se comportará como si devolviera una función de limpieza vacía. -### Why synchronization may need to happen more than once {/*why-synchronization-may-need-to-happen-more-than-once*/} +### Por qué la sincronización puede necesitar suceder mas de una vez {/*why-synchronization-may-need-to-happen-more-than-once*/} -Imagine this `ChatRoom` component receives a `roomId` prop that the user picks in a dropdown. Let's say that initially the user picks the `"general"` room as the `roomId`. Your app displays the `"general"` chat room: +Imagina que este componente `ChatRoom` recibe una prop `roomId` que el usuario selecciona de un menú desplegable. Digamos que inicialmente el usuario selecciona la sala `"general"` como el `roomId`. Tu aplicación muestra la sala de chat `"general"`: ```js {3} const serverUrl = 'https://localhost:1234'; function ChatRoom({ roomId /* "general" */ }) { // ... - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } ``` -After the UI is displayed, React will run your Effect to **start synchronizing.** It connects to the `"general"` room: +Después que se muestre la UI, React ejecutará el Efecto para **iniciar la sincronización.** Se conecta a la sala `"general"`: ```js {3,4} function ChatRoom({ roomId /* "general" */ }) { useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Connects to the "general" room + const connection = createConnection(serverUrl, roomId); // Conecta a la sala "general" connection.connect(); return () => { - connection.disconnect(); // Disconnects from the "general" room + connection.disconnect(); // Desconecta de la sala "general" }; }, [roomId]); // ... ``` -So far, so good. +Hasta ahora, todo bien. -Later, the user picks a different room in the dropdown (for example, `"travel"`). First, React will update the UI: +Luego, el usuario selecciona una sala diferente en el menú desplegable (por ejemplo, `"travel"`). Primero, React actualizará la UI: ```js {1} function ChatRoom({ roomId /* "travel" */ }) { // ... - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } ``` -Think about what should happen next. The user sees that `"travel"` is the selected chat room in the UI. However, the Effect that ran the last time is still connected to the `"general"` room. **The `roomId` prop has changed, so what your Effect did back then (connecting to the `"general"` room) no longer matches the UI.** +Piensa en que debería suceder luego. El usuario ve que `"travel"` es la sala de chat en la UI. Sin embargo, el Efecto que se ejecutó la última vez aun está conectada a la sala `"general"`. **La prop `"roomId"` ha cambiado, asi que lo que el Efecto hizo en ese entonces (conectarse a la sala `"general"`) ya no coincide con la UI.** -At this point, you want React to do two things: +En este punto, deseas que React haga dos cosas: -1. Stop synchronizing with the old `roomId` (disconnect from the `"general"` room) -2. Start synchronizing with the new `roomId` (connect to the `"travel"` room) +1. Que detenga la sincronización con el antiguo `roomId` (desconectarse de la sala `"general"`) +2. Que inicie la sincronización con el nuevo `roomId` (conectarse a la sala `"travel"`) -**Luckily, you've already taught React how to do both of these things!** Your Effect's body specifies how to start synchronizing, and your cleanup function specifies how to stop synchronizing. All that React needs to do now is to call them in the correct order and with the correct props and state. Let's see how exactly that happens. +**Afortunadamente, ¡ya has enseñado a React a cómo hacer ambas cosas!** El cuerpo del Efecto especifica cómo iniciar la sincronización, y su función de limpieza especifica cómo detener la sincronización. Todo lo que React necesita hacer ahora es llamarlos en el orden correcto y con las props y estado correctos. Veamos cómo sucede esto exactamente. -### How React re-synchronizes your Effect {/*how-react-re-synchronizes-your-effect*/} +### Cómo React vuelve a sincronizar tu Efecto {/*how-react-re-synchronizes-your-effect*/} -Recall that your `ChatRoom` component has received a new value for its `roomId` prop. It used to be `"general"`, and now it is `"travel"`. React needs to re-synchronize your Effect to re-connect you to a different room. +Recuerda que tu componente `ChatRoom` había recibido un nuevo valor para su prop `roomId`. Solía ser `"general"`, y ahora es `"travel"`. React necesita volver a sincronizar tu Efecto para volver a conectar a una sala diferente. -To **stop synchronizing,** React will call the cleanup function that your Effect returned after connecting to the `"general"` room. Since `roomId` was `"general"`, the cleanup function disconnects from the `"general"` room: +Para **detener la sincronización,** React llamará a la función de limpieza que tu Efecto devolvió después de conectarse a la sala `"general"`. Dado que `roomId` era `"general"`, la función de limpieza se desconecta de la sala `"general"`: ```js {6} function ChatRoom({ roomId /* "general" */ }) { useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Connects to the "general" room + const connection = createConnection(serverUrl, roomId); // Se conecta a la sala "general" connection.connect(); return () => { - connection.disconnect(); // Disconnects from the "general" room + connection.disconnect(); // Se desconecta de la sala "general" }; // ... ``` -Then React will run the Effect that you've provided during this render. This time, `roomId` is `"travel"` so it will **start synchronizing** to the `"travel"` chat room (until its cleanup function is eventually called too): +Luego, React ejecutará el Efecto que hayas proporcionado durante este renderizado. Esta vez, `roomId` es `"travel"` por lo que **comenzará a sincronizar** la sala de chat `"travel"` (hasta que su función de limpieza eventualmente también se llame): ```js {3,4} function ChatRoom({ roomId /* "travel" */ }) { useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Connects to the "travel" room + const connection = createConnection(serverUrl, roomId); // Se conecta a la sala "travel" connection.connect(); // ... ``` -Thanks to this, you're now connected to the same room that the user chose in the UI. Disaster averted! +Gracias a esto, ahora estás conectado a la misma sala que el usuario eligió en la UI. ¡Desastre evitado! -Every time after your component re-renders with a different `roomId`, your Effect will re-synchronize. For example, let's say the user changes `roomId` from `"travel"` to `"music"`. React will again **stop synchronizing** your Effect by calling its cleanup function (disconnecting you from the `"travel"` room). Then it will **start synchronizing** again by running its body with the new `roomId` prop (connecting you to the `"music"` room). +Cada vez que tu componente se vuelve a renderizar con un `roomId` diferente, tu Efecto se volverá a sincronizar. Por ejemplo, digamos que el usuario cambió el `roomId` de `"travel"` a `"music"`. React volverá a **detener la sincronización** de tu Efecto llamando a la función de limpieza (desconectándose de la sala `"travel"`). Luego, **comenzará a sincronizarse** nuevamente al ejecutar su cuerpo con la nueva prop `roomId` (conectándose a la sala `"music"`). -Finally, when the user goes to a different screen, `ChatRoom` unmounts. Now there is no need to stay connected at all. React will **stop synchronizing** your Effect one last time and disconnect you from the `"music"` chat room. +Finalmente, cuando el usuario vaya a una pantalla diferente, `ChatRoom` se desmonta. Ahora no hay necesidad de permanecer conectado en absoluto. React **detendrá la sincronización** de tu Efecto por última vez y te desconectará de la sala de chat `"music"`. -### Thinking from the Effect's perspective {/*thinking-from-the-effects-perspective*/} +### Pensar desde la perspectiva del Efecto {/*thinking-from-the-effects-perspective*/} -Let's recap everything that's happened from the `ChatRoom` component's perspective: +Recapitulemos todo lo que sucedió desde la perspectiva del componente `ChatRoom`: -1. `ChatRoom` mounted with `roomId` set to `"general"` -1. `ChatRoom` updated with `roomId` set to `"travel"` -1. `ChatRoom` updated with `roomId` set to `"music"` -1. `ChatRoom` unmounted +1. `ChatRoom` se montó con `roomId` establecido en `"general"` +2. `ChatRoom` se actualizó con `roomId` establecido en `"travel"` +3. `ChatRoom` se actualizó con `roomId` establecido en `"music"` +4. `ChatRoom` se desmontó -During each of these points in the component's lifecycle, your Effect did different things: +Durante cada uno de estos puntos en el ciclo de vida del componente, tu Efecto hizo diferentes cosas: -1. Your Effect connected to the `"general"` room -1. Your Effect disconnected from the `"general"` room and connected to the `"travel"` room -1. Your Effect disconnected from the `"travel"` room and connected to the `"music"` room -1. Your Effect disconnected from the `"music"` room +1. Tu Efecto se conectó a la sala `"general"` +2. Tu Efecto se desconectó de la sala `"general"` y se conectó a la sala `"travel"` +3. Tu Efecto se desconectó de la sala `"travel"` y se conectó a la sala `"music"` +4. Tu Efecto se desconectó de la sala `"music"` -Now let's think about what happened from the perspective of the Effect itself: +Ahora pensemos qué sucedió desde la perspectiva del Efecto mismo: ```js useEffect(() => { - // Your Effect connected to the room specified with roomId... + // Tu Efecto se conectó a la sala especificada con el roomId... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { - // ...until it disconnected + // ...hasta que se desconectó connection.disconnect(); }; }, [roomId]); ``` -This code's structure might inspire you to see what happened as a sequence of non-overlapping time periods: +Esta estructura de código podría inspirarte a ver lo que sucedió como una secuencia de períodos de tiempo no superpuestos: -1. Your Effect connected to the `"general"` room (until it disconnected) -1. Your Effect connected to the `"travel"` room (until it disconnected) -1. Your Effect connected to the `"music"` room (until it disconnected) +1. Tu Efecto se conectó a la sala `"general"` (hasta que se desconectó) +2. Tu Efecto se conectó a la sala `"travel"` (hasta que se desconectó) +3. Tu Efecto se conectó a la sala `"music"` (hasta que se desconectó) -Previously, you were thinking from the component's perspective. When you looked from the component's perspective, it was tempting to think of Effects as "callbacks" or "lifecycle events" that fire at a specific time like "after a render" or "before unmount". This way of thinking gets complicated very fast, so it's best to avoid. +Previamente, pensabas desde la perspectiva del componente. Cuando miraste desde la perspectiva del componente, era tentador pensar en los Efectos como "_callbacks_" o "eventos del ciclo de vida" que se disparaban en un momento específico como "después de renderizar" o "antes de desmontar". Esta forma de pensar se complica muy rápido, por lo que es mejor evitarla. -**Instead, always focus on a single start/stop cycle at a time. It shouldn't matter whether a component is mounting, updating, or unmounting. All you need to do is to describe how to start synchronization and how to stop it. If you do it well, your Effect will be resilient to being started and stopped as many times as it's needed.** +**En su lugar, siempre concéntrate en un solo ciclo de inicio/parada a la vez. No debería importar si un componente se está montando, actualizando o desmontando. Lo único que necesitas hacer es describir cómo iniciar la sincronización y cómo detenerla. Si lo haces bien, tu Efecto será resistente a ser iniciado y detenido tantas veces como sea necesario.** -This might remind you how you don't think whether a component is mounting or updating when you write the rendering logic that creates JSX. You describe what should be on the screen, and React [figures out the rest.](/learn/reacting-to-input-with-state) +Esto podría recordarte cómo no pensar si un componente se está montando o actualizando cuando escribes la lógica de renderizado que crea JSX. Describes lo que debería estar en la pantalla y React [se encarga del resto.](/learn/reacting-to-input-with-state) -### How React verifies that your Effect can re-synchronize {/*how-react-verifies-that-your-effect-can-re-synchronize*/} +### Cómo React verifica que tu Efecto pueda volver a sincronizarse {/*how-react-verifies-that-your-effect-can-re-synchronize*/} -Here is a live example that you can play with. Press "Open chat" to mount the `ChatRoom` component: +Aquí hay un ejemplo en vivo con el que puedes experimentar. Presiona "Abrir chat" para montar el componente `ChatRoom`: @@ -222,7 +222,7 @@ function ChatRoom({ roomId }) { connection.connect(); return () => connection.disconnect(); }, [roomId]); - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } export default function App() { @@ -231,18 +231,18 @@ export default function App() { return ( <> {show &&
} {show && } @@ -253,13 +253,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor. return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectando de "' + roomId + '" en ' + serverUrl); } }; } @@ -272,49 +272,49 @@ button { margin-left: 10px; }
-Notice that when the component mounts for the first time, you see three logs: +Observa que cuando el componente se monta por primera vez, ves tres registros: -1. `✅ Connecting to "general" room at https://localhost:1234...` *(development-only)* -1. `❌ Disconnected from "general" room at https://localhost:1234.` *(development-only)* -1. `✅ Connecting to "general" room at https://localhost:1234...` +1. `✅ Conectando a la sala "general" en https://localhost:1234...` *(solo en desarrollo)* +1. `❌ Desconectando de "general" en https://localhost:1234.` *(solo en desarrollo)* +1. `✅ Conectando a la sala "general" en https://localhost:1234...` -The first two logs are development-only. In development, React always remounts each component once. +Los primeros dos registros son solo para desarrollo. En desarrollo, React siempre vuelve a montar cada componente una vez. -**React verifies that your Effect can re-synchronize by forcing it to do that immediately in development.** This might remind you of opening a door and closing it an extra time to check if the door lock works. React starts and stops your Effect one extra time in development to check [you've implemented its cleanup well.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) +**React verifica que tu Efecto puede volver a sincronizarse forzándolo a hacerlo inmediatamente en desarrollo** Esto puede recordarte a cuando abres una puerta y la cierras una vez más para verificar si la cerradura funciona. React inicia y detiene tu Efecto una vez adicional en desarrollo para comprobar que [has implementado su limpieza adecuadamente.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) -The main reason your Effect will re-synchronize in practice is if some data it uses has changed. In the sandbox above, change the selected chat room. Notice how, when the `roomId` changes, your Effect re-synchronizes. +La razón principal por la que tu Efecto volverá a sincronizarse en la práctica es si algunos de los datos que utiliza han cambiado. En el sandbox de arriba, cambia la sala de chat seleccionada. Observa cómo, cuando cambia el valor de `roomId`, tu Efecto vuelve a sincronizarse. -However, there are also more unusual cases in which re-synchronization is necessary. For example, try editing the `serverUrl` in the sandbox above while the chat is open. Notice how the Effect re-synchronizes in response to your edits to the code. In the future, React may add more features that rely on re-synchronization. +Sin embargo, también hay casos más inusuales en los que es necesario que vuelva a sincronizar. Por ejemplo, intenta editar el `serverUrl` en el sandbox de arriba mientras el chat está abierto. Observa cómo el Efecto vuelve a sincronizar en respuesta a tus ediciones en el código. En el futuro, React puede agregar más características que dependan de volver a sincronizar. -### How React knows that it needs to re-synchronize the Effect {/*how-react-knows-that-it-needs-to-re-synchronize-the-effect*/} +### Cómo React conoce que es necesario volver a sincronizar el Efecto {/*how-react-knows-that-it-needs-to-re-synchronize-the-effect*/} -You might be wondering how React knew that your Effect needed to re-synchronize after `roomId` changes. It's because *you told React* that its code depends on `roomId` by including it in the [list of dependencies:](/learn/synchronizing-with-effects#step-2-specify-the-effect-dependencies) +Podrías estarte preguntando cómo React conoce que tu Efecto necesita volverse a sincronizar luego de que el `roomId` cambia. Es porque *le dijiste a React* que su código depende de `roomId` al incluirlo en la [lista de dependencias:](/learn/synchronizing-with-effects#step-2-specify-the-effect-dependencies) ```js {1,3,8} -function ChatRoom({ roomId }) { // The roomId prop may change over time +function ChatRoom({ roomId }) { // La prop roomId puede cambiar con el tiempo useEffect(() => { - const connection = createConnection(serverUrl, roomId); // This Effect reads roomId + const connection = createConnection(serverUrl, roomId); // Este Efecto lee roomId connection.connect(); return () => { connection.disconnect(); }; - }, [roomId]); // So you tell React that this Effect "depends on" roomId + }, [roomId]); // Entonces le dices a React que este Efecto "depende de" roomId // ... ``` -Here's how this works: +Así es como funciona esto: -1. You knew `roomId` is a prop, which means it can change over time. -2. You knew that your Effect reads `roomId` (so its logic depends on a value that may change later). -3. This is why you specified it as your Effect's dependency (so that it re-synchronizes when `roomId` changes). +1. Sabías que `roomId` es una prop, lo que significa que puede cambiar con el tiempo. +2. Sabías que tu Efecto lee `roomId` (porque lo usas para crear la conexión). +3. Es por esto que lo especificaste como la dependencia de tu Efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). -Every time after your component re-renders, React will look at the array of dependencies that you have passed. If any of the values in the array is different from the value at the same spot that you passed during the previous render, React will re-synchronize your Effect. +Cada vez que tu componente se vuelve a renderizar, React mirará el _array_ de dependencias que has pasado. Si alguno de los valores en el _array_ de dependencias es diferente del valor en el mismo lugar que pasaste durante el renderizado anterior, React volverá a sincronizar tu Efecto. -For example, if you passed `["general"]` during the initial render, and later you passed `["travel"]` during the next render, React will compare `"general"` and `"travel"`. These are different values (compared with [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), so React will re-synchronize your Effect. On the other hand, if your component re-renders but `roomId` has not changed, your Effect will remain connected to the same room. +Por ejemplo, si pasaste `["general"]` durante el renderizado inicial, y luego pasaste `["travel"]` durante el siguiente renderizado, React comparará `"general"` y `"travel"`. Estos son valores diferentes (comparados con [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), por lo que React volverá a sincronizar tu Efecto. Por otro lado, si tu componente se vuelve a renderizar pero `roomId` no ha cambiado, tu Efecto permanecerá conectado a la misma sala. -### Each Effect represents a separate synchronization process {/*each-effect-represents-a-separate-synchronization-process*/} +### Cada Efecto representa un proceso de sincronización separado {/*each-effect-represents-a-separate-synchronization-process*/} -Resist adding unrelated logic to your Effect only because this logic needs to run at the same time as an Effect you already wrote. For example, let's say you want to send an analytics event when the user visits the room. You already have an Effect that depends on `roomId`, so you might feel tempted to add the analytics call there: +Resiste la tentación de agregar lógica no relacionada a tu Efecto solo porque esta lógica necesita ejecutarse al mismo tiempo que un Efecto que ya escribiste. Por ejemplo, digamos que quieres enviar un evento de análisis cuando el usuario visita la sala. Ya tienes un Efecto que depende de `roomId`, por lo que podrías sentirte tentado a agregar la llamada de análisis allí: ```js {3} function ChatRoom({ roomId }) { @@ -330,7 +330,7 @@ function ChatRoom({ roomId }) { } ``` -But imagine you later add another dependency to this Effect that needs to re-establish the connection. If this Effect re-synchronizes, it will also call `logVisit(roomId)` for the same room, which you did not intend. Logging the visit **is a separate process** from connecting. Write them as two separate Effects: +Pero imagina que más tarde agregas otra dependencia a este Efecto que necesita restablecer la conexión. Si este Efecto se vuelve a sincronizar, también llamará a `logVisit(roomId)` para la misma sala, lo cual no pretendías. Registrar la visita **es un proceso separado** de la conexión. Escríbelos como dos Efectos separados: ```js {2-4} function ChatRoom({ roomId }) { @@ -346,13 +346,13 @@ function ChatRoom({ roomId }) { } ``` -**Each Effect in your code should represent a separate and independent synchronization process.** +**Cada Efecto en tu código debe representar un proceso de sincronización separado e independiente.** -In the above example, deleting one Effect wouldn’t break the other Effect's logic. This is a good indication that they synchronize different things, and so it made sense to split them up. On the other hand, if you split up a cohesive piece of logic into separate Effects, the code may look "cleaner" but will be [more difficult to maintain.](/learn/you-might-not-need-an-effect#chains-of-computations) This is why you should think whether the processes are same or separate, not whether the code looks cleaner. +En el ejemplo de arriba, eliminar un Efecto no rompería la lógica del otro Efecto. Esta es una buena indicación de que sincronizan cosas diferentes, por lo que tiene sentido dividirlos. Por otro lado, si divides una pieza cohesiva de lógica en Efectos separados, el código puede verse "más limpio", pero será [más difícil de mantener.](/learn/you-might-not-need-an-effect#chains-of-computations) Es por esto que debes pensar si los procesos son iguales o diferentes, no si el código se ve más limpio. -## Effects "react" to reactive values {/*effects-react-to-reactive-values*/} +## Los Efectos "reaccionan" a valores reactivos {/*effects-react-to-reactive-values*/} -Your Effect reads two variables (`serverUrl` and `roomId`), but you only specified `roomId` as a dependency: +Tu Efecto lee dos variables (`serverUrl` y `roomId`), pero solo especificaste `roomId` como una dependencia: ```js {5,10} const serverUrl = 'https://localhost:1234'; @@ -369,32 +369,32 @@ function ChatRoom({ roomId }) { } ``` -Why doesn't `serverUrl` need to be a dependency? +¿Por qué no se especifica `serverUrl` como una dependencia? -This is because the `serverUrl` never changes due to a re-render. It's always the same no matter how many times the component re-renders and why. Since `serverUrl` never changes, it wouldn't make sense to specify it as a dependency. After all, dependencies only do something when they change over time! +Esto es porque el `serverUrl` nunca cambia debido a un rerenderizado. Siempre es el mismo sin importar cuántas veces se vuelva a renderizar el componente y por qué. Dado que `serverUrl` nunca cambia, no tendría sentido especificarlo como una dependencia. Después de todo, ¡las dependencias solo hacen algo cuando cambian con el tiempo! -On the other hand, `roomId` may be different on a re-render. **Props, state, and other values declared inside the component are _reactive_ because they're calculated during rendering and participate in the React data flow.** +Por otro lado, `roomId` puede ser diferente en un rerenderizado. **Las props, el estado y otros valores declarados dentro del componente son _reactivos_ porque se calculan durante el renderizado y participan en el flujo de datos de React.** -If `serverUrl` was a state variable, it would be reactive. Reactive values must be included in dependencies: +Si `serverUrl` fuera una variable de estado, sería reactiva. Los valores reactivos deben incluirse en las dependencias: ```js {2,5,10} -function ChatRoom({ roomId }) { // Props change over time - const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // State may change over time +function ChatRoom({ roomId }) { // Las props cambian con el tiempo + const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // El estado puede cambiar con el tiempo useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Your Effect reads props and state + const connection = createConnection(serverUrl, roomId); // Tu Efecto lee props y estado connection.connect(); return () => { connection.disconnect(); }; - }, [roomId, serverUrl]); // So you tell React that this Effect "depends on" on props and state + }, [roomId, serverUrl]); // Entonces le dices a React que este Efecto "depende de" las props y el estado // ... } ``` -By including `serverUrl` as a dependency, you ensure that the Effect re-synchronizes after it changes. +Al incluir `serverUrl` como una dependencia, te aseguras de que el Efecto se vuelva a sincronizar después de que cambie. -Try changing the selected chat room or edit the server URL in this sandbox: +Intenta cambiar la sala de chat seleccionada o editar la URL del servidor en este _sandbox_: @@ -414,13 +414,13 @@ function ChatRoom({ roomId }) { return ( <> -

Welcome to the {roomId} room!

+

¡Bienvenido a la sala {roomId}!

); } @@ -430,14 +430,14 @@ export default function App() { return ( <>
@@ -449,13 +449,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real en realidad se conectaría al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectado de la sala "' + roomId + '" en ' + serverUrl); } }; } @@ -468,11 +468,11 @@ button { margin-left: 10px; }
-Whenever you change a reactive value like `roomId` or `serverUrl`, the Effect re-connects to the chat server. +Cada vez que cambies un valor reactivo como `roomId` o `serverUrl`, el Efecto se vuelve a conectar al servidor del chat. -### What an Effect with empty dependencies means {/*what-an-effect-with-empty-dependencies-means*/} +### ¿Qué significa un Efecto con dependencias vacías? {/*what-an-effect-with-empty-dependencies-means*/} -What happens if you move both `serverUrl` and `roomId` outside the component? +¿Qué pasa si mueves tanto `serverUrl` como `roomId` fuera del componente? ```js {1,2} const serverUrl = 'https://localhost:1234'; @@ -485,14 +485,14 @@ function ChatRoom() { return () => { connection.disconnect(); }; - }, []); // ✅ All dependencies declared + }, []); // ✅ Todas las dependencias declaradas // ... } ``` -Now your Effect's code does not use *any* reactive values, so its dependencies can be empty (`[]`). +Ahora el código de tu Efecto no usa *ningún* valor reactivo, por lo que sus dependencias pueden estar vacías (`[]`). -Thinking from the component's perspective, the empty `[]` dependency array means this Effect connects to the chat room only when the component mounts, and disconnects only when the component unmounts. (Keep in mind that React would still [re-synchronize it an extra time](#how-react-verifies-that-your-effect-can-re-synchronize) in development to stress-test your logic.) +Pensando desde la perspectiva del componente, el _array_ de dependencias vacías `[]` significa que este Efecto se conecta a la sala de chat solo cuando el componente se monta, y se desconecta solo cuando el componente se desmonta. (Ten en cuenta que React aún [se volvería a sincronizar una vez más](#how-react-verifies-that-your-effect-can-re-synchronize) en desarrollo para probar tu lógica.) @@ -510,7 +510,7 @@ function ChatRoom() { connection.connect(); return () => connection.disconnect(); }, []); - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } export default function App() { @@ -518,7 +518,7 @@ export default function App() { return ( <> {show &&
} {show && } @@ -529,13 +529,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real en realidad conectaría al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectado de la sala "' + roomId + '" en ' + serverUrl); } }; } @@ -548,52 +548,52 @@ button { margin-left: 10px; }
-However, if you [think from the Effect's perspective,](#thinking-from-the-effects-perspective) you don't need to think about mounting and unmounting at all. What's important is you've specified what your Effect does to start and stop synchronizing. Today, it has no reactive dependencies. But if you ever want the user to change `roomId` or `serverUrl` over time (and they would become reactive), your Effect's code won't change. You will only need to add them to the dependencies. +Sin embargo, si [piensas desde la perspectiva del Efecto,](#thinking-from-the-effects-perspective) no necesitas pensar en montar y desmontar en absoluto. Lo importante es que has especificado lo que tu Efecto hace para comenzar y detener la sincronización. Hoy, no tiene dependencias reactivas. Pero si alguna vez quieres que el usuario cambie `roomId` o `serverUrl` con el tiempo (y se volverían reactivos), el código de tu Efecto no cambiará. Solo necesitarás agregarlos a las dependencias. -### All variables declared in the component body are reactive {/*all-variables-declared-in-the-component-body-are-reactive*/} +### Todas las variables declaradas en el cuerpo del componente son reactivas {/*all-variables-declared-in-the-component-body-are-reactive*/} -Props and state aren't the only reactive values. Values that you calculate from them are also reactive. If the props or state change, your component will re-render, and the values calculated from them will also change. This is why all variables from the component body used by the Effect should be in the Effect dependency list. +Las props y el estado no son los únicos valores reactivos. Los valores que calculas a partir de ellos también son reactivos. Si las props o el estado cambian, tu componente se volverá a renderizar, y los valores calculados a partir de ellos también cambiarán. Es por eso que todas las variables del cuerpo del componente utilizadas por el Efecto deben estar en la lista de dependencias del Efecto. -Let's say that the user can pick a chat server in the dropdown, but they can also configure a default server in settings. Suppose you've already put the settings state in a [context](/learn/scaling-up-with-reducer-and-context) so you read the `settings` from that context. Now you calculate the `serverUrl` based on the selected server from props and the default server: +Digamos que el usuario puede elegir un servidor de chat en el menú desplegable, pero también puede configurar un servidor predeterminado en la configuración. Supongamos que ya has puesto el estado de configuración en un [contexto](/learn/scaling-up-with-reducer-and-context) para que leas la `configuración` de ese contexto. Ahora calculas `serverUrl` en función del servidor seleccionado de las props y el servidor predeterminado: ```js {3,5,10} -function ChatRoom({ roomId, selectedServerUrl }) { // roomId is reactive - const settings = useContext(SettingsContext); // settings is reactive - const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl is reactive +function ChatRoom({ roomId, selectedServerUrl }) { // roomId es reactivo + const settings = useContext(SettingsContext); // settings es reactivo + const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl es reactivo useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Your Effect reads roomId and serverUrl + const connection = createConnection(serverUrl, roomId); // Tu Efecto lee roomId y serverUrl connection.connect(); return () => { connection.disconnect(); }; - }, [roomId, serverUrl]); // So it needs to re-synchronize when either of them changes! + }, [roomId, serverUrl]); // ¡Así que necesita volver a sincronizar cuando cualquiera de ellas cambia! // ... } ``` -In this example, `serverUrl` is not a prop or a state variable. It's a regular variable that you calculate during rendering. But it's calculated during rendering, so it can change due to a re-render. This is why it's reactive. +En este ejemplo, `serverUrl` no es una prop ni una variable de estado. Es una variable regular que calculas durante el renderizado. Al ser calculada durante el renderizado, puede cambiar debido a un nuevo renderizado. Es por eso que es reactiva. -**All values inside the component (including props, state, and variables in your component's body) are reactive. Any reactive value can change on a re-render, so you need to include reactive values as Effect's dependencies.** +**Todos los valores dentro del componente (incluidas las props, el estado y las variables en el cuerpo de tu componente) son reactivos. Cualquier valor reactivo puede cambiar en un nuevo renderizado, por lo que debes incluir los valores reactivos como dependencias del Efecto.** -In other words, Effects "react" to all values from the component body. +En otras palabras, los Efectos "reaccionan" a todos los valores del cuerpo del componente. -#### Can global or mutable values be dependencies? {/*can-global-or-mutable-values-be-dependencies*/} +#### ¿Pueden los valores globales o mutables ser dependencias? {/*can-global-or-mutable-values-be-dependencies*/} -Mutable values (including global variables) aren't reactive. +Los valores mutables (incluidas las variables globales) no son reactivos. -**A mutable value like [`location.pathname`](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname) can't be a dependency.** It's mutable, so it can change at any time completely outside of the React rendering data flow. Changing it wouldn't trigger a re-render of your component. Therefore, even if you specified it in the dependencies, React *wouldn't know* to re-synchronize the Effect when it changes. This also breaks the rules of React because reading mutable data during rendering (which is when you calculate the dependencies) breaks [purity of rendering.](/learn/keeping-components-pure) Instead, you should read and subscribe to an external mutable value with [`useSyncExternalStore`.](/learn/you-might-not-need-an-effect#subscribing-to-an-external-store) +**Un valor mutable como [`location.pathname`](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname) no puede ser una dependencia.** Es mutable, por lo que puede cambiar en cualquier momento fuera del flujo de datos de renderizado de React. Cambiarlo no activaría un nuevo renderizado de tu componente. Por lo tanto, incluso si lo especificaras en las dependencias, React *no sabría* volver a sincronizar el Efecto cuando cambia. Esto también rompe las reglas de React porque leer datos mutables durante el renderizado (que es cuando calculas las dependencias) rompe la [pureza del renderizado.](/learn/keeping-components-pure) En su lugar, debes leer y suscribirte a un valor mutable externo con [`useSyncExternalStore`.](/learn/you-might-not-need-an-effect#subscribing-to-an-external-store) -**A mutable value like [`ref.current`](/reference/react/useRef#reference) or things you read from it also can't be a dependency.** The ref object returned by `useRef` itself can be a dependency, but its `current` property is intentionally mutable. It lets you [keep track of something without triggering a re-render.](/learn/referencing-values-with-refs) But since changing it doesn't trigger a re-render, it's not a reactive value, and React won't know to re-run your Effect when it changes. +**Un valor mutable como [`ref.current`](/reference/react/useRef#reference) o cosas que lees de él tampoco pueden ser una dependencia.** El objeto ref devuelto por `useRef` en sí puede ser una dependencia, pero su propiedad `current` es intencionalmente mutable. Te permite [mantener un seguimiento de algo sin activar un nuevo renderizado.](/learn/referencing-values-with-refs) Pero como cambiarlo no activa un nuevo renderizado, no es un valor reactivo, y React no sabrá volver a ejecutar tu Efecto cuando cambie. -As you'll learn below on this page, a linter will check for these issues automatically. +Como aprenderás a continuación en esta página, un linter verificará automáticamente estos problemas. -### React verifies that you specified every reactive value as a dependency {/*react-verifies-that-you-specified-every-reactive-value-as-a-dependency*/} +### React verifica que especificaste cada valor reactivo como una dependencia {/*react-verifies-that-you-specified-every-reactive-value-as-a-dependency*/} -If your linter is [configured for React,](/learn/editor-setup#linting) it will check that every reactive value used by your Effect's code is declared as its dependency. For example, this is a lint error because both `roomId` and `serverUrl` are reactive: +Si tu linter está [configurado para React,](/learn/editor-setup#linting) verificará que cada valor reactivo utilizado por el código de tu Efecto se declare como su dependencia. Por ejemplo, este es un error de lint porque tanto `roomId` como `serverUrl` son reactivos: @@ -601,25 +601,25 @@ If your linter is [configured for React,](/learn/editor-setup#linting) it will c import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; -function ChatRoom({ roomId }) { // roomId is reactive - const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl is reactive +function ChatRoom({ roomId }) { // roomId es reactivo + const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl es reactivo useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => connection.disconnect(); - }, []); // <-- Something's wrong here! + }, []); // <-- Algo está mal aquí! return ( <> -

Welcome to the {roomId} room!

+

¡Bienvenido a la sala {roomId}!

); } @@ -629,14 +629,14 @@ export default function App() { return ( <>
@@ -648,13 +648,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real en realidad se conectaría al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectado de la sala "' + roomId + '" en ' + serverUrl); } }; } @@ -667,41 +667,41 @@ button { margin-left: 10px; }
-This may look like a React error, but really React is pointing out a bug in your code. Both `roomId` and `serverUrl` may change over time, but you're forgetting to re-synchronize your Effect when they change. You will remain connected to the initial `roomId` and `serverUrl` even after the user picks different values in the UI. +Esto puede parecer un error de React, pero en realidad React está señalando un error en tu código. Tanto `roomId` como `serverUrl` pueden cambiar con el tiempo, pero olvidaste volver a sincronizar tu Efecto cuando cambian. Seguirás conectado a la `roomId` y `serverUrl` iniciales incluso después de que el usuario elija valores diferentes en la interfaz de usuario. -To fix the bug, follow the linter's suggestion to specify `roomId` and `serverUrl` as dependencies of your Effect: +Para solucionar el error, sigue la sugerencia del linter de especificar `roomId` y `serverUrl` como dependencias de tu Efecto: ```js {9} -function ChatRoom({ roomId }) { // roomId is reactive - const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl is reactive +function ChatRoom({ roomId }) { // roomId es reactivo + const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl es reactivo useEffect(() => { const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; - }, [serverUrl, roomId]); // ✅ All dependencies declared + }, [serverUrl, roomId]); // ✅ Todas las dependencias están declaradas // ... } ``` -Try this fix in the sandbox above. Verify that the linter error is gone, and the chat re-connects when needed. +Intenta esta solución en el _sandbox_ de arriba. Verifica que el error del linter haya desaparecido y que el chat se vuelva a conectar cuando sea necesario. -In some cases, React *knows* that a value never changes even though it's declared inside the component. For example, the [`set` function](/reference/react/useState#setstate) returned from `useState` and the ref object returned by [`useRef`](/reference/react/useRef) are *stable*--they are guaranteed to not change on a re-render. Stable values aren't reactive, so you may omit them from the list. Including them is allowed: they won't change, so it doesn't matter. +En algunos casos, React *sabe* que un valor nunca cambia aunque se declare dentro del componente. Por ejemplo, la función [`set`](/reference/react/useState#setstate) devuelta por `useState` y el objeto ref devuelto por [`useRef`](/reference/react/useRef) son *estables*--se garantiza que no cambiarán en un nuevo renderizado. Los valores estables no son reactivos, por lo que puedes omitirlos de la lista. Incluirlos está permitido: no cambiarán, por lo que no importa. -### What to do when you don't want to re-synchronize {/*what-to-do-when-you-dont-want-to-re-synchronize*/} +### ¿Qué hacer cuando no quieres volver a sincronizar? {/*what-to-do-when-you-dont-want-to-re-synchronize*/} -In the previous example, you've fixed the lint error by listing `roomId` and `serverUrl` as dependencies. +En los ejemplos previos, has arreglado el error del linter enumerando `roomId` y `serverUrl` como dependencias. -**However, you could instead "prove" to the linter that these values aren't reactive values,** i.e. that they *can't* change as a result of a re-render. For example, if `serverUrl` and `roomId` don't depend on rendering and always have the same values, you can move them outside the component. Now they don't need to be dependencies: +**Sin embargo, podrías en cambio "demostrar" al linter que estos valores no son reactivos,** es decir, que *no pueden* cambiar como resultado de un nuevo renderizado. Por ejemplo, si `serverUrl` y `roomId` no dependen del renderizado y siempre tienen los mismos valores, puedes moverlos fuera del componente. Ahora no necesitan ser dependencias: ```js {1,2,11} -const serverUrl = 'https://localhost:1234'; // serverUrl is not reactive -const roomId = 'general'; // roomId is not reactive +const serverUrl = 'https://localhost:1234'; // serverUrl no es reactivo +const roomId = 'general'; // roomId no es reactivo function ChatRoom() { useEffect(() => { @@ -710,80 +710,80 @@ function ChatRoom() { return () => { connection.disconnect(); }; - }, []); // ✅ All dependencies declared + }, []); // ✅ Declaradas todas las dependencias // ... } ``` -You can also move them *inside the Effect.* They aren't calculated during rendering, so they're not reactive: +También puedes moverlos *dentro del Efecto.* No se calculan durante el renderizado, por lo que no son reactivos: ```js {3,4,10} function ChatRoom() { useEffect(() => { - const serverUrl = 'https://localhost:1234'; // serverUrl is not reactive - const roomId = 'general'; // roomId is not reactive + const serverUrl = 'https://localhost:1234'; // serverUrl no es reactivo + const roomId = 'general'; // roomId no es reactivo const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { connection.disconnect(); }; - }, []); // ✅ All dependencies declared + }, []); // ✅ Declaradas todas las dependencias // ... } ``` -**Effects are reactive blocks of code.** They re-synchronize when the values you read inside of them change. Unlike event handlers, which only run once per interaction, Effects run whenever synchronization is necessary. +**Los Efectos son bloques de código reactivos.** Se vuelven a sincronizar cuando los valores que lees dentro de ellos cambian. A diferencia de los manejadores de eventos, que solo se ejecutan una vez por interacción, los Efectos se ejecutan cada vez que es necesaria la sincronización. -**You can't "choose" your dependencies.** Your dependencies must include every [reactive value](#all-variables-declared-in-the-component-body-are-reactive) you read in the Effect. The linter enforces this. Sometimes this may lead to problems like infinite loops and to your Effect re-synchronizing too often. Don't fix these problems by suppressing the linter! Here's what to try instead: +**No puedes "elegir" tus dependencias.** Tus dependencias deben incluir cada [valor reactivo](#all-variables-declared-in-the-component-body-are-reactive) que lees en el Efecto. El linter hace cumplir esto. A veces esto puede conducir a problemas como bucles infinitos y a que tu Efecto se vuelva a sincronizar demasiado a menudo. ¡No soluciones estos problemas suprimiendo el linter! Esto es lo que debes intentar en su lugar: -* **Check that your Effect represents an independent synchronization process.** If your Effect doesn't synchronize anything, [it might be unnecessary.](/learn/you-might-not-need-an-effect) If it synchronizes several independent things, [split it up.](#each-effect-represents-a-separate-synchronization-process) +* **Verifica que tu Efecto represente un proceso de sincronización independiente.** Si tu Efecto no sincroniza nada, [podría ser innecesario.](/learn/you-might-not-need-an-effect) Si sincroniza varias cosas independientes, [divídelo.](#each-effect-represents-a-separate-synchronization-process) -* **If you want to read the latest value of props or state without "reacting" to it and re-synchronizing the Effect,** you can split your Effect into a reactive part (which you'll keep in the Effect) and a non-reactive part (which you'll extract into something called an _Effect Event_). [Read about separating Events from Effects.](/learn/separating-events-from-effects) +* **Si quieres leer la última versión de las props o el estado sin "reaccionar" a ellas y volver a sincronizar el Efecto,** puedes dividir tu Efecto en una parte reactiva (que mantendrás en el Efecto) y una parte no reactiva (que extraerás en algo llamado un _Evento de Efecto_). [Lee sobre cómo separar los Eventos de los Efectos.](/learn/separating-events-from-effects) -* **Avoid relying on objects and functions as dependencies.** If you create objects and functions during rendering and then read them from an Effect, they will be different on every render. This will cause your Effect to re-synchronize every time. [Read more about removing unnecessary dependencies from Effects.](/learn/removing-effect-dependencies) +* **Evita confiar en objetos y funciones como dependencias.** Si creas objetos y funciones durante el renderizado y luego los lees desde un Efecto, serán diferentes en cada renderizado. Esto hará que tu Efecto se vuelva a sincronizar cada vez. [Lee más sobre cómo eliminar las dependencias innecesarias de los Efectos.](/learn/removing-effect-dependencies) -The linter is your friend, but its powers are limited. The linter only knows when the dependencies are *wrong*. It doesn't know *the best* way to solve each case. If the linter suggests a dependency, but adding it causes a loop, it doesn't mean the linter should be ignored. You need to change the code inside (or outside) the Effect so that that value isn't reactive and doesn't *need* to be a dependency. +El linter es tu amigo, pero sus poderes son limitados. El linter solo sabe cuando las dependencias son *incorrectas*. No sabe la *mejor* manera de resolver cada caso. Si el linter sugiere una dependencia, pero agregarla causa un bucle, no significa que el linter deba ser ignorado. Necesitas cambiar el código dentro (o fuera) del Efecto para que ese valor no sea reactivo y no *necesite* ser una dependencia. -If you have an existing codebase, you might have some Effects that suppress the linter like this: +Si tienes una base de código existente, es posible que tengas algunos Efectos que supriman el linter de esta manera: ```js {3-4} useEffect(() => { // ... - // 🔴 Avoid suppressing the linter like this: + // 🔴 Evita suprimir el linter de esta manera: // eslint-ignore-next-line react-hooks/exhaustive-deps }, []); ``` -On the [next](/learn/separating-events-from-effects) [pages](/learn/removing-effect-dependencies), you'll learn how to fix this code without breaking the rules. It's always worth fixing! +En la [siguiente](/learn/separating-events-from-effects) [página](/learn/removing-effect-dependencies), aprenderás cómo arreglar este código sin romper las reglas. ¡Siempre vale la pena arreglarlo! -- Components can mount, update, and unmount. -- Each Effect has a separate lifecycle from the surrounding component. -- Each Effect describes a separate synchronization process that can *start* and *stop*. -- When you write and read Effects, think from each individual Effect's perspective (how to start and stop synchronization) rather than from the component's perspective (how it mounts, updates, or unmounts). -- Values declared inside the component body are "reactive". -- Reactive values should re-synchronize the Effect because they can change over time. -- The linter verifies that all reactive values used inside the Effect are specified as dependencies. -- All errors flagged by the linter are legitimate. There's always a way to fix the code to not break the rules. +- Los componentes pueden montarse, actualizarse y desmontarse. +- Cada Efecto tiene un ciclo de vida separado del componente circundante. +- Cada Efecto describe un proceso de sincronización separado que puede *iniciarse* y *detenerse*. +- Cuando escribes y lees Efectos, piensa desde la perspectiva de cada Efecto individual (cómo iniciar y detener la sincronización) en lugar de desde la perspectiva del componente (cómo se monta, actualiza o desmonta). +- Valores declarados dentro del cuerpo del componente son "reactivos". +- Valores reactivos deben volver a sincronizar el Efecto porque pueden cambiar con el tiempo. +- El linter verifica que todos los valores reactivos usados dentro del Efecto estén especificados como dependencias. +- Todas las banderas de error del linter son legítimas. Siempre hay una manera de arreglar el código para que no rompa las reglas. -#### Fix reconnecting on every keystroke {/*fix-reconnecting-on-every-keystroke*/} +#### Arreglar la reconexión en cada pulsación de tecla {/*fix-reconnecting-on-every-keystroke*/} -In this example, the `ChatRoom` component connects to the chat room when the component mounts, disconnects when it unmounts, and reconnects when you select a different chat room. This behavior is correct, so you need to keep it working. +En este ejemplo, el componente `ChatRoom` se conecta a la sala de chat cuando el componente se monta, se desconecta cuando se desmonta y se vuelve a conectar cuando seleccionas una sala de chat diferente. Este comportamiento es correcto, por lo que debes mantenerlo funcionando. -However, there is a problem. Whenever you type into the message box input at the bottom, `ChatRoom` *also* reconnects to the chat. (You can notice this by clearing the console and typing into the input.) Fix the issue so that this doesn't happen. +Sin embargo, hay un problema. Cada vez que escribes en el cuadro de entrada de mensajes en la parte inferior, `ChatRoom` *también* se reconecta al chat. (Puedes notarlo borrando la consola y escribiendo en la entrada.) Arregla el problema para que esto no suceda. -You might need to add a dependency array for this Effect. What dependencies should be there? +Podrías necesitar agregar un _array_ de dependencias al Efecto. ¿Qué dependencias deberían estar allí? @@ -806,7 +806,7 @@ function ChatRoom({ roomId }) { return ( <> -

Welcome to the {roomId} room!

+

¡Bienvenido a la sala {roomId}!

setMessage(e.target.value)} @@ -820,14 +820,14 @@ export default function App() { return ( <>
@@ -839,13 +839,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real en realidad conectaría al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectado de la sala "' + roomId + '" en ' + serverUrl); } }; } @@ -860,7 +860,7 @@ button { margin-left: 10px; } -This Effect didn't have a dependency array at all, so it re-synchronized after every re-render. First, add a dependency array. Then, make sure that every reactive value used by the Effect is specified in the array. For example, `roomId` is reactive (because it's a prop), so it should be included in the array. This ensures that when the user selects a different room, the chat reconnects. On the other hand, `serverUrl` is defined outside the component. This is why it doesn't need to be in the array. +Este Efecto no tenía un _array_ de dependencias en absoluto, por lo que se volvió a sincronizar después de cada renderizado. Primero, agrega un _array_ de dependencias. Luego, asegúrate de que cada valor reactivo utilizado por el Efecto esté especificado en el _array_. Por ejemplo, `roomId` es reactivo (porque es una prop), por lo que debe incluirse en el _array_. Esto asegura que cuando el usuario selecciona una sala de chat diferente, el chat se reconecta. Por otro lado, `serverUrl` se define fuera del componente. Es por eso que no necesita estar en el _array_. @@ -881,7 +881,7 @@ function ChatRoom({ roomId }) { return ( <> -

Welcome to the {roomId} room!

+

¡Bienvenido a la sala {roomId}!

setMessage(e.target.value)} @@ -895,14 +895,14 @@ export default function App() { return ( <>
@@ -914,13 +914,13 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // A real implementation would actually connect to the server + // Una implementación real en realidad conectaría al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...'); + console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl); + console.log('❌ Desconectado de la sala "' + roomId + '" en ' + serverUrl); } }; } @@ -935,15 +935,15 @@ button { margin-left: 10px; }
-#### Switch synchronization on and off {/*switch-synchronization-on-and-off*/} +#### Activar y desactivar la sincronización {/*switch-synchronization-on-and-off*/} -In this example, an Effect subscribes to the window [`pointermove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event) event to move a pink dot on the screen. Try hovering over the preview area (or touching the screen if you're on a mobile device), and see how the pink dot follows your movement. +En este ejemplo, un Efecto se suscribe al evento de ventana [`pointermove`](https://developer.mozilla.org/en-US/docs/Web/API/Element/pointermove_event) para mover un punto rosa en la pantalla. Intenta pasar el cursor sobre el área de vista previa (o tocar la pantalla si estás en un dispositivo móvil) y ve cómo el punto rosa sigue tu movimiento. -There is also a checkbox. Ticking the checkbox toggles the `canMove` state variable, but this state variable is not used anywhere in the code. Your task is to change the code so that when `canMove` is `false` (the checkbox is ticked off), the dot should stop moving. After you toggle the checkbox back on (and set `canMove` to `true`), the box should follow the movement again. In other words, whether the dot can move or not should stay synchronized to whether the checkbox is checked. +También hay una casilla de verificación. Al marcar la casilla, se cambia la variable de estado `canMove`, pero esta variable de estado no se usa en ninguna parte del código. Tu tarea es cambiar el código para que cuando `canMove` sea `false` (la casilla está desactivada), el punto deje de moverse. Después de volver a activar la casilla (y establecer `canMove` en `true`), la caja debe seguir el movimiento nuevamente. En otras palabras, si el punto puede moverse o no debe permanecer sincronizado con la marca de la casilla. -You can't declare an Effect conditionally. However, the code inside the Effect can use conditions! +No puedes declarar un Efecto condicionalmente. Sin embargo, ¡el código dentro del Efecto puede usar condiciones! @@ -971,7 +971,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-One solution is to wrap the `setPosition` call into an `if (canMove) { ... }` condition: +Una solución es envolver la llamada `setPosition` en una condición `if (canMove) { ... }`: @@ -1029,7 +1029,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-Alternatively, you could wrap the *event subscription* logic into an `if (canMove) { ... }` condition: +Alternativamente, podrías envolver la lógica de *suscripción al evento* en una condición `if (canMove) { ... }`: @@ -1085,7 +1085,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-In both of these cases, `canMove` is a reactive variable that you read inside the Effect. This is why it must be specified in the list of Effect dependencies. This ensures that the Effect re-synchronizes after every change to its value. +En ambos casos, `canMove` es una variable reactiva que lees dentro del Efecto. Por eso debe especificarse en la lista de dependencias del Efecto. Esto asegura que el Efecto se vuelva a sincronizar después de cada cambio en su valor. -#### Investigate a stale value bug {/*investigate-a-stale-value-bug*/} +#### Investiga un error de valor obsoleto {/*investigate-a-stale-value-bug*/} -In this example, the pink dot should move when the checkbox is on, and should stop moving when the checkbox is off. The logic for this has already been implemented: the `handleMove` event handler checks the `canMove` state variable. +En este ejemplo, el punto rosa debería moverse cuando el checkbox está activado, y debería dejar de moverse cuando el checkbox está desactivado. La lógica para esto ya se ha implementado: el manejador de eventos `handleMove` comprueba la variable de estado `canMove`. -However, for some reason, the `canMove` state variable inside `handleMove` appears to be "stale": it's always `true`, even after you tick off the checkbox. How is this possible? Find the mistake in the code and fix it. +Sin embargo, por alguna razón, la variable de estado `canMove` dentro de `handleMove` parece estar "obsoleta": siempre es `true`, incluso después de desmarcar el checkbox. ¿Cómo es posible esto? Encuentra el error en el código y arréglalo. -If you see a linter rule being suppressed, remove the suppression! That's where the mistakes usually are. +Si ves una regla de linter suprimida, ¡elimina la supresión! Ahí es donde suelen estar los errores. @@ -1157,7 +1157,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-The problem with the original code was suppressing the dependency linter. If you remove the suppression, you'll see that this Effect depends on the `handleMove` function. This makes sense: `handleMove` is declared inside the component body, which makes it a reactive value. Every reactive value must be specified as a dependency, or it can potentially get stale over time! +El problema con el código original era suprimir el linter de dependencias. Si eliminas la supresión, verás que este Efecto depende de la función `handleMove`. Esto tiene sentido: `handleMove` se declara dentro del cuerpo del componente, lo que lo convierte en un valor reactivo. Cada valor reactivo debe especificarse como una dependencia, o puede volverse obsoleto con el tiempo. -The author of the original code has "lied" to React by saying that the Effect does not depend (`[]`) on any reactive values. This is why React did not re-synchronize the Effect after `canMove` has changed (and `handleMove` with it). Because React did not re-synchronize the Effect, the `handleMove` attached as a listener is the `handleMove` function created during the initial render. During the initial render, `canMove` was `true`, which is why `handleMove` from the initial render will forever see that value. +El autor del código original le ha "mentido" a React diciendo que el Efecto no depende (`[]`) de ningún valor reactivo. Por eso React no volvió a sincronizar el Efecto después de que `canMove` cambió (y `handleMove` con él). Como React no volvió a sincronizar el Efecto, el `handleMove` adjunto como oyente es la función `handleMove` creada durante el renderizado inicial. Durante el renderizado inicial, `canMove` era `true`, por lo que `handleMove` del renderizado inicial siempre verá ese valor. -**If you never suppress the linter, you will never see problems with stale values.** There are a few different ways to solve this bug, but you should always start by removing the linter suppression. Then change the code to fix the lint error. +**Si nunca suprimes el linter, nunca verás problemas con valores obsoletos.** Hay algunas formas diferentes de resolver este error, pero siempre debes comenzar eliminando la supresión del linter. Luego cambia el código para corregir el error del linter. -You can change the Effect dependencies to `[handleMove]`, but since it's going to be a newly defined function for every render, you might as well remove dependencies array altogether. Then the Effect *will* re-synchronize after every re-render: +Puedes cambiar las dependencias del Efecto a `[handleMove]`, pero como va a ser una función recién definida para cada renderizado, puedes eliminar por completo el _array_ de dependencias. Entonces el Efecto *se volverá a sincronizar* después de cada renderizado: @@ -1222,7 +1222,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-This solution works, but it's not ideal. If you put `console.log('Resubscribing')` inside the Effect, you'll notice that it resubscribes after every re-render. Resubscribing is fast, but it would still be nice to avoid doing it so often. +Esta solución funciona, pero no es ideal. Si pones `console.log('Resubscribing')` dentro del Efecto, notarás que se vuelve a suscribir después de cada rerenderizado. La resuscripción es rápida, pero aún así sería bueno evitar hacerlo tan a menudo. -A better fix would be to move the `handleMove` function *inside* the Effect. Then `handleMove` won't be a reactive value, and so your Effect won't depend on a function. Instead, it will need to depend on `canMove` which your code now reads from inside the Effect. This matches the behavior you wanted, since your Effect will now stay synchronized with the value of `canMove`: +Una mejor solución sería mover la función `handleMove` *dentro* del Efecto. Entonces `handleMove` no será un valor reactivo, por lo que tu Efecto no dependerá de una función. En cambio, necesitará depender de `canMove` que ahora lee desde dentro del Efecto. Esto coincide con el comportamiento que deseabas, ya que tu Efecto ahora se mantendrá sincronizado con el valor de `canMove`: @@ -1281,7 +1281,7 @@ export default function App() { checked={canMove} onChange={e => setCanMove(e.target.checked)} /> - The dot is allowed to move + El punto puede moverse
-Try adding `console.log('Resubscribing')` inside the Effect body and notice that now it only resubscribes when you toggle the checkbox (`canMove` changes) or edit the code. This makes it better than the previous approach that always resubscribed. +Intenta agregar `console.log('Resubscribing')` dentro del cuerpo del Efecto y notarás que ahora solo se vuelve a suscribir cuando cambias el valor del checkbox (`canMove` cambia) o editas el código. Esto lo hace mejor que el enfoque anterior que siempre se volvía a suscribir. -You'll learn a more general approach to this type of problem in [Separating Events from Effects.](/learn/separating-events-from-effects) +Aprenderás un enfoque más general para este tipo de problema en [Separar Eventos de Efectos.](/learn/separating-events-from-effects) -#### Fix a connection switch {/*fix-a-connection-switch*/} +#### Solucionar un cambio de conexión {/*fix-a-connection-switch*/} -In this example, the chat service in `chat.js` exposes two different APIs: `createEncryptedConnection` and `createUnencryptedConnection`. The root `App` component lets the user choose whether to use encryption or not, and then passes down the corresponding API method to the child `ChatRoom` component as the `createConnection` prop. +En este ejemplo, el servicio de chat en `chat.js` expone dos APIs diferentes: `createEncryptedConnection` y `createUnencryptedConnection`. El componente raíz `App` permite al usuario elegir si usar o no el cifrado, y luego pasa el método de API correspondiente al componente secundario `ChatRoom` como la prop `createConnection`. -Notice that initially, the console logs say the connection is not encrypted. Try toggling the checkbox on: nothing will happen. However, if you change the selected room after that, then the chat will reconnect *and* enable encryption (as you'll see from the console messages). This is a bug. Fix the bug so that toggling the checkbox *also* causes the chat to reconnect. +Nota que inicialmente, los registros de la consola dicen que la conexión no está cifrada. Intenta cambiar el valor del checkbox: no sucederá nada. Sin embargo, si cambias la sala de chat seleccionada después de eso, entonces el chat se reconectará *y* habilitará el cifrado (como verás en los mensajes de la consola). Esto es un error. Arregla el error para que el cambio del checkbox *también* haga que el chat se reconecte. -Suppressing the linter is always suspicious. Could this be a bug? +Suprimir el linter es siempre sospechoso. ¿Podría ser esto un error? @@ -1343,14 +1343,14 @@ export default function App() { return ( <>
Welcome to the {roomId} room!; + return

¡Bienvenido a la sala {roomId}!

; } ``` ```js chat.js export function createEncryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)'); + console.log('✅ 🔐 Conectando a "' + roomId + '... (cifrado)'); }, disconnect() { - console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)'); + console.log('❌ 🔐 Desconectando de la sala "' + roomId + '" (cifrado)'); } }; } export function createUnencryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '... (unencrypted)'); + console.log('✅ Conectando a "' + roomId + '... (sin cifrar)'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)'); + console.log('❌ Desconectando de la sala "' + roomId + '" (sin cifrar)'); } }; } @@ -1423,7 +1423,7 @@ label { display: block; margin-bottom: 10px; } -If you remove the linter suppression, you will see a lint error. The problem is that `createConnection` is a prop, so it's a reactive value. It can change over time! (And indeed, it should--when the user ticks the checkbox, the parent component passes a different value of the `createConnection` prop.) This is why it should be a dependency. Include it in the list to fix the bug: +Si quitas la supresión del linter, verás un error de lint. El problema es que `createConnection` es una prop, por lo que es un valor reactivo. ¡Puede cambiar con el tiempo! (Y de hecho, debería hacerlo, cuando el usuario marca el checkbox, el componente padre pasa un valor diferente de la prop `createConnection`). Por eso debería ser una dependencia. Inclúyelo en la lista para solucionar el error: @@ -1441,14 +1441,14 @@ export default function App() { return ( <>
connection.disconnect(); }, [roomId, createConnection]); - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } ``` ```js chat.js export function createEncryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)'); + console.log('✅ 🔐 Conectando a "' + roomId + '... (cifrado)'); }, disconnect() { - console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)'); + console.log('❌ 🔐 Desconectando de la sala "' + roomId + '" (cifrado)'); } }; } export function createUnencryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '... (unencrypted)'); + console.log('✅ Conectando a "' + roomId + '... (sin cifrar)'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)'); + console.log('❌ Desconectando de la sala "' + roomId + '" (sin cifrar)'); } }; } @@ -1518,7 +1518,7 @@ label { display: block; margin-bottom: 10px; }
-It is correct that `createConnection` is a dependency. However, this code is a bit fragile because someone could edit the `App` component to pass an inline function as the value of this prop. In that case, its value would be different every time the `App` component re-renders, so the Effect might re-synchronize too often. To avoid this, you can pass `isEncrypted` down instead: +Es correcto que `createConnection` sea una dependencia. Sin embargo, este código es un poco frágil porque alguien podría editar el componente `App` para pasar una función en línea como valor de esta prop. En ese caso, su valor sería diferente cada vez que el componente `App` se vuelva a renderizar, por lo que el Efecto podría volver a sincronizarse demasiado a menudo. Para evitar esto, puedes pasar `isEncrypted` en su lugar: @@ -1532,14 +1532,14 @@ export default function App() { return ( <>
connection.disconnect(); }, [roomId, isEncrypted]); - return

Welcome to the {roomId} room!

; + return

¡Bienvenido a la sala {roomId}!

; } ``` ```js chat.js export function createEncryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)'); + console.log('✅ 🔐 Conectando a "' + roomId + '... (cifrado)'); }, disconnect() { - console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)'); + console.log('❌ 🔐 Desconectando de la sala "' + roomId + '" (cifrado)'); } }; } export function createUnencryptedConnection(roomId) { - // A real implementation would actually connect to the server + // Una implementación real se conectaría realmente al servidor return { connect() { - console.log('✅ Connecting to "' + roomId + '... (unencrypted)'); + console.log('✅ Conectando a "' + roomId + '... (sin cifrar)'); }, disconnect() { - console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)'); + console.log('❌ Desconectando de la sala "' + roomId + '" (sin cifrar)'); } }; } @@ -1613,21 +1613,21 @@ label { display: block; margin-bottom: 10px; }
-In this version, the `App` component passes a boolean prop instead of a function. Inside the Effect, you decide which function to use. Since both `createEncryptedConnection` and `createUnencryptedConnection` are declared outside the component, they aren't reactive, and don't need to be dependencies. You'll learn more about this in [Removing Effect Dependencies.](/learn/removing-effect-dependencies) +En esta versión, el componente `App` pasa una prop booleana en lugar de una función. Dentro del Efecto, decides qué función usar. Dado que tanto `createEncryptedConnection` como `createUnencryptedConnection` se declaran fuera del componente, no son reactivos y no necesitan ser dependencias. Aprenderás más sobre esto en [Eliminar dependencias de los Efectos.](/learn/removing-effect-dependencies)
-#### Populate a chain of select boxes {/*populate-a-chain-of-select-boxes*/} +#### Rellenar una cadena de cuadros de selección {/*populate-a-chain-of-select-boxes*/} -In this example, there are two select boxes. One select box lets the user pick a planet. Another select box lets the user pick a place *on that planet.* The second box doesn't work yet. Your task is to make it show the places on the chosen planet. +En este ejemplo, hay dos cuadros de selección. Un cuadro de selección permite al usuario elegir un planeta. Otro cuadro de selección permite al usuario elegir un lugar *en ese planeta*. El segundo cuadro no funciona todavía. Tu tarea es hacer que muestre los lugares en el planeta elegido. -Look at how the first select box works. It populates the `planetList` state with the result from the `"/planets"` API call. The currently selected planet's ID is kept in the `planetId` state variable. You need to find where to add some additional code so that the `placeList` state variable is populated with the result of the `"/planets/" + planetId + "/places"` API call. +Mira cómo funciona el primer cuadro de selección. Rellena la variable de estado `planetList` con el resultado de la llamada a la API `"/planets"`. El ID del planeta actualmente seleccionado se mantiene en la variable de estado `planetId`. Necesitas encontrar dónde agregar algún código adicional para que la variable de estado `placeList` se rellene con el resultado de la llamada a la API `"/planets/" + planetId + "/places"`. -If you implement this right, selecting a planet should populate the place list. Changing a planet should change the place list. +Si lo haces bien, seleccionar un planeta debería rellenar la lista de lugares. Cambiar un planeta debería cambiar la lista de lugares. -If you have two independent synchronization processes, you need to write two separate Effects. +Si tienes dos procesos de sincronización independientes, necesitas escribir dos Efectos separados. @@ -1648,9 +1648,9 @@ export default function Page() { let ignore = false; fetchData('/planets').then(result => { if (!ignore) { - console.log('Fetched a list of planets.'); + console.log('Se obtuvo una lista de planetas.'); setPlanetList(result); - setPlanetId(result[0].id); // Select the first planet + setPlanetId(result[0].id); // Se selecciona el primer planeta } }); return () => { @@ -1661,7 +1661,7 @@ export default function Page() { return ( <>
-

You are going to: {placeId || '???'} on {planetId || '???'}

+

Estás yendo a: {placeId || '???'} en {planetId || '???'}

); } @@ -1773,12 +1773,12 @@ label { display: block; margin-bottom: 10px; } -There are two independent synchronization processes: +Hay dos procesos de sincronización independientes: -- The first select box is synchronized to the remote list of planets. -- The second select box is synchronized to the remote list of places for the current `planetId`. +- La primera caja de selección está sincronizada con la lista remota de planetas. +- La segunda caja de selección está sincronizada con la lista remota de lugares para el `planetId` actual. -This is why it makes sense to describe them as two separate Effects. Here's an example of how you could do this: +Por eso tiene sentido describirlos como dos Efectos separados. Aquí tienes un ejemplo de cómo podrías hacerlo: @@ -1797,9 +1797,9 @@ export default function Page() { let ignore = false; fetchData('/planets').then(result => { if (!ignore) { - console.log('Fetched a list of planets.'); + console.log('Se obtuvo una lista de planetas.'); setPlanetList(result); - setPlanetId(result[0].id); // Select the first planet + setPlanetId(result[0].id); // Selecciona el primer planeta } }); return () => { @@ -1809,16 +1809,16 @@ export default function Page() { useEffect(() => { if (planetId === '') { - // Nothing is selected in the first box yet + // No hay nada seleccionado en el primer cuadro todavía return; } let ignore = false; fetchData('/planets/' + planetId + '/places').then(result => { if (!ignore) { - console.log('Fetched a list of places on "' + planetId + '".'); + console.log('Obtener lista de lugares en "' + planetId + '".'); setPlaceList(result); - setPlaceId(result[0].id); // Select the first place + setPlaceId(result[0].id); // Selecciona el primer lugar } }); return () => { @@ -1829,7 +1829,7 @@ export default function Page() { return ( <>
-

You are going to: {placeId || '???'} on {planetId || '???'}

+

Estás yendo a: {placeId || '???'} en {planetId || '???'}

); } @@ -1939,9 +1939,9 @@ label { display: block; margin-bottom: 10px; }
-This code is a bit repetitive. However, that's not a good reason to combine it into a single Effect! If you did this, you'd have to combine both Effect's dependencies into one list, and then changing the planet would refetch the list of all planets. Effects are not a tool for code reuse. +Este código es un poco repetitivo. Sin embargo, ¡no es una buena razón para combinarlo en un solo Efecto! Si hicieras esto, tendrías que combinar las dependencias de ambos Efectos en una sola lista, y luego cambiar el planeta volvería a buscar la lista de todos los planetas. Los Efectos no son una herramienta para reutilizar código. -Instead, to reduce repetition, you can extract some logic into a custom Hook like `useSelectOptions` below: +En su lugar, para reducir la repetición, puede extraer algo de lógica en un Hook de React personalizado como `useSelectOptions` a continuación: @@ -1965,7 +1965,7 @@ export default function Page() { return ( <>
-

You are going to: {placeId || '...'} on {planetId || '...'}

+

Estás yendo a: {placeId || '...'} en {planetId || '...'}

); } @@ -2102,7 +2102,7 @@ label { display: block; margin-bottom: 10px; }
-Check the `useSelectOptions.js` tab in the sandbox to see how it works. Ideally, most Effects in your application should eventually be replaced by custom Hooks, whether written by you or by the community. Custom Hooks hide the synchronization logic, so the calling component doesn't know about the Effect. As you keep working on your app, you'll develop a palette of Hooks to choose from, and eventually you won't need to write Effects in your components very often. +Verifica la pestaña `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Efectos en tu aplicación eventualmente deberían reemplazarse por Hooks personalizados, ya sea escritos por ti o por la comunidad. Los Hooks personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no sabe sobre el Efecto. A medida que sigas trabajando en tu aplicación, desarrollarás una paleta de Hooks para elegir, y eventualmente no necesitarás escribir Efectos en tus componentes con mucha frecuencia.
diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 960aa4395..c0f7316f0 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -177,7 +177,7 @@ "path": "/learn/you-might-not-need-an-effect" }, { - "title": "Lifecycle of Reactive Effects", + "title": "Ciclo de vida de los Efectos reactivos", "path": "/learn/lifecycle-of-reactive-effects" }, {