From 94d3c8e664d76d10442c72f61a3df489eabc2718 Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Thu, 1 Jun 2023 21:53:09 -0500 Subject: [PATCH 01/10] Translate "Lifecycle of Reactive Effects" --- .../learn/lifecycle-of-reactive-effects.md | 615 +++++++++--------- 1 file changed, 308 insertions(+), 307 deletions(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 5d9554a1a..430ca856b 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: para 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 los últimos _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á 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 su código cambia, la sincronización tendrá que suceder mas 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 su 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 un `roomId` _prop_ 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 el _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, `"trave"`). Primero, React actualizará el _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 el _UI_. Sin embargo, el efecto que se ejecutó la última vez aun está conectada a la sala `"general"`. **El `"roomId"` _prop_ ha cambiado, asi que lo que el efecto hizo en ese entonces (conectarse a la sala `"general"`) ya no coincide con el _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. Detener la sincronización con el antiguo `roomId`(desconectarse de la sala `"general"`) +2. Iniciar 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 `roomId` _prop_. 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); // Conectar a la sala "general" connection.connect(); return () => { - connection.disconnect(); // Disconnects from the "general" room + connection.disconnect(); // Desconectar 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 es eventualmente llamado también): ```js {3,4} function ChatRoom({ roomId /* "travel" */ }) { useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Connects to the "travel" room + const connection = createConnection(serverUrl, roomId); // 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 el 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 su 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 el nuevo `roomId` _prop_ (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` montado con `roomId` establecido en `"general"` +2. `ChatRoom` actualizado con `roomId` establecido en `"travel"` +3. `ChatRoom` actualizado con `roomId` establecido en `"music"` +4. `ChatRoom` desmontado -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 en que 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 especificado 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, tu pensabas desde la perspectiva del componente. Cuando tu 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 Effect 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 representación 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...` *(development-only)* +1. `❌ Desconectando de "general" en https://localhost:1234.` *(development-only)* +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 forzando lo 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 se 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ía estarse 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 }) { // El props 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 un 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 especificó como la dependencia de su 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á la matriz de dependencias que has pasado. Si alguno de los valores en la matriz 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*/} +## 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 re-renderizado. 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 re-renderizado. **Los 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 }) { // 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 A real implementation 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. +Cuando sea 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 la `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á 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 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](#todas-las-variables-declaradas-en-el-cuerpo-del-componente-son-reactivas) 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.](#cada-efecto-representa-un-proceso-de-sincronización-separado) -* **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 *iniciar* y *detener*. +- 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,16 @@ button { margin-left: 10px; }
+#### Activar y desactivar la sincronización {/*switch-synchronization-on-and-off*/} #### Switch synchronization on and off {/*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 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 si la casilla está marcada. -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 +972,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 +1030,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 +1086,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*/} +#### Ivestiga un error de valor absoluto {/*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 +1158,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 codigo 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` haya cambiado (y `handleMove` con él). Como React no volvió a sincronizar el efecto, el `handleMove` adjunto como oyente es la función `handleMove` creada durante la representación inicial. Durante la representación inicial, `canMove` era `true`, por lo que `handleMove` de la representación 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 representación, puedes eliminar por completo la matriz de dependencias. Entonces el efecto *se volverá a sincronizar* después de cada representación: @@ -1222,7 +1223,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 solició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 representación. 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 +1282,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) +Aprenerás un enfoque más general para este tipo de problema en [Separating Events from Effects.](/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 API 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 cambiar el 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 +1344,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 +1424,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 +1442,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 +1519,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 Effect podría volver a sincronizarse demasiado a menudo. Para evitar esto, puedes pasar `isEncrypted` en su lugar: @@ -1532,14 +1533,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 +1614,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 Effect, 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 [Eliminación de dependencias de Effect.](/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 Effects separados. @@ -1648,9 +1649,9 @@ export default function Page() { let ignore = false; fetchData('/planets').then(result => { if (!ignore) { - console.log('Fetched a list of planets.'); + console.log('Obtener una lista de planetas.'); setPlanetList(result); - setPlanetId(result[0].id); // Select the first planet + setPlanetId(result[0].id); // Seleccione el primer planeta } }); return () => { @@ -1661,7 +1662,7 @@ export default function Page() { return ( <>
-

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

+

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

); } @@ -1773,12 +1774,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 Effects separados. Aquí tienes un ejemplo de cómo podrías hacerlo: @@ -1797,9 +1798,9 @@ export default function Page() { let ignore = false; fetchData('/planets').then(result => { if (!ignore) { - console.log('Fetched a list of planets.'); + console.log('Obtener 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 +1810,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 +1830,7 @@ export default function Page() { return ( <>
-

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

+

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

); } @@ -1939,9 +1940,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 codigo es un poco repetitivo. Sin embargo, ¡no es una buena razón para combinarlo en un solo Effect! Si hicieras esto, tendrías que combinar las dependencias de ambos Effect en una sola lista, y luego cambiar el planeta volvería a buscar la lista de todos los planetas. Los Effects 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 personalizado como `useSelectOptions` a continuación: @@ -1965,7 +1966,7 @@ export default function Page() { return ( <>
-

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

+

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

); } @@ -2102,7 +2103,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 el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks personalizados, ya sea escritos por usted o por la comunidad. Los Hooks personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Effect. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia.
From ed37a32cbddddef6f671c2a944bbaddca015247b Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Fri, 2 Jun 2023 08:08:34 -0500 Subject: [PATCH 02/10] Translate "Lifecycle of Reactive Effects" sidebar --- src/sidebarLearn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 78814b1ac..0ea7e8490 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" }, { From 6b7c3497d300cb7730bd5c8b637d43c57efe0082 Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Fri, 2 Jun 2023 08:18:57 -0500 Subject: [PATCH 03/10] remove: old title in wrong language --- src/content/learn/lifecycle-of-reactive-effects.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 430ca856b..d2c819413 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -936,7 +936,6 @@ button { margin-left: 10px; } #### Activar y desactivar la sincronización {/*switch-synchronization-on-and-off*/} -#### Switch synchronization on and off {/*switch-synchronization-on-and-off*/} En este ejemplo, un efecto 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. From ef72234148d1e50d48fca6d48c2f588d41d3a72e Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Fri, 2 Jun 2023 08:48:44 -0500 Subject: [PATCH 04/10] Update with glossary terminology --- .../learn/lifecycle-of-reactive-effects.md | 196 +++++++++--------- 1 file changed, 98 insertions(+), 98 deletions(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index d2c819413..1ce464b2f 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -1,19 +1,19 @@ --- -title: 'Ciclo de vida de los efectos reactivos' +title: 'Ciclo de vida de los Efectos reactivos' --- -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: para 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 los últimos _props_ y estado. +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: para 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 los últimos _props_ y estado. -- 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 +- 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 @@ -21,7 +21,7 @@ Los efectos tienen un diferente ciclo de vida al de los componentes. Los compone -## El ciclo de vida de un efecto {/*the-lifecycle-of-an-effect*/} +## El ciclo de vida de un Efecto {/*the-lifecycle-of-an-effect*/} Cada componente de React pasa por el mismo ciclo de vida: @@ -29,9 +29,9 @@ Cada componente de React pasa por el mismo ciclo de vida: - 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. -**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 su código cambia, la sincronización tendrá que suceder mas o menos a menudo. +**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 su código cambia, la sincronización tendrá que suceder mas o menos a menudo. -Para ilustrar este punto, considera este efecto que conecta su componente a un servidor de chat: +Para ilustrar este punto, considera este Efecto que conecta su componente a un servidor de chat: ```js const serverUrl = 'https://localhost:1234'; @@ -48,7 +48,7 @@ function ChatRoom({ roomId }) { } ``` -El cuerpo de tu efecto especifica cómo **iniciar la sincronización:** +El cuerpo de tu Efecto especifica cómo **iniciar la sincronización:** ```js {2-3} // ... @@ -60,7 +60,7 @@ El cuerpo de tu efecto especifica cómo **iniciar la sincronización:** // ... ``` -La función de limpieza devuelta por tu efecto especifica cómo **detener la sincronización:** +La función de limpieza devuelta por tu Efecto especifica cómo **detener la sincronización:** ```js {5} // ... @@ -78,7 +78,7 @@ Veamos _por qué_ esto es necesario, _cuándo_ sucede, y _cómo_ se puede contro -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. +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. @@ -95,7 +95,7 @@ function ChatRoom({ roomId /* "general" */ }) { } ``` -Después que se muestre el _UI_, React ejecutará el efecto para **iniciar la sincronización.** Se conecta a la sala `"general"`: +Después que se muestre el _UI_, React ejecutará el Efecto para **iniciar la sincronización.** Se conecta a la sala `"general"`: ```js {3,4} function ChatRoom({ roomId /* "general" */ }) { @@ -120,20 +120,20 @@ function ChatRoom({ roomId /* "travel" */ }) { } ``` -Piensa en que debería suceder luego. El usuario ve que `"travel"` es la sala de chat en el _UI_. Sin embargo, el efecto que se ejecutó la última vez aun está conectada a la sala `"general"`. **El `"roomId"` _prop_ ha cambiado, asi que lo que el efecto hizo en ese entonces (conectarse a la sala `"general"`) ya no coincide con el _UI_.** +Piensa en que debería suceder luego. El usuario ve que `"travel"` es la sala de chat en el _UI_. Sin embargo, el Efecto que se ejecutó la última vez aun está conectada a la sala `"general"`. **El `"roomId"` _prop_ ha cambiado, asi que lo que el Efecto hizo en ese entonces (conectarse a la sala `"general"`) ya no coincide con el _UI_.** En este punto, deseas que React haga dos cosas: 1. Detener la sincronización con el antiguo `roomId`(desconectarse de la sala `"general"`) 2. Iniciar la sincronización con el nuevo `roomId`(conectarse a la sala `"travel"`) -**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. +**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. -### Cómo React vuelve a sincronizar tu efecto {/*how-react-re-synchronizes-your-effect*/} +### Cómo React vuelve a sincronizar tu Efecto {/*how-react-re-synchronizes-your-effect*/} -Recuerda que tu componente `ChatRoom` había recibido un nuevo valor para su `roomId` _prop_. Solía ser `"general"`, y ahora es `"travel"`. React necesita volver a sincronizar tu efecto para volver a conectar a una sala diferente. +Recuerda que tu componente `ChatRoom` había recibido un nuevo valor para su `roomId` _prop_. Solía ser `"general"`, y ahora es `"travel"`. React necesita volver a sincronizar tu Efecto para volver a conectar a una sala diferente. -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"`: +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" */ }) { @@ -146,7 +146,7 @@ function ChatRoom({ roomId /* "general" */ }) { // ... ``` -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 es eventualmente llamado también): +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 es eventualmente llamado también): ```js {3,4} function ChatRoom({ roomId /* "travel" */ }) { @@ -158,11 +158,11 @@ function ChatRoom({ roomId /* "travel" */ }) { Gracias a esto, ahora estás conectado a la misma sala que el usuario eligió en el UI. ¡Desastre evitado! -Cada vez que su 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 el nuevo `roomId` _prop_ (conectándose a la sala `"music"`). +Cada vez que su 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 el nuevo `roomId` _prop_ (conectándose a la sala `"music"`). -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"`. +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"`. -### Pensar desde la perspectiva del efecto {/*thinking-from-the-effects-perspective*/} +### Pensar desde la perspectiva del Efecto {/*thinking-from-the-effects-perspective*/} Recapitulemos todo lo que sucedió desde la perspectiva del componente `ChatRoom`: @@ -171,18 +171,18 @@ Recapitulemos todo lo que sucedió desde la perspectiva del componente `ChatRoom 3. `ChatRoom` actualizado con `roomId` establecido en `"music"` 4. `ChatRoom` desmontado -Durante cada uno de estos puntos en el ciclo de vida del componente, tu efecto hizo diferentes cosas: +Durante cada uno de estos puntos en el ciclo de vida del componente, tu Efecto hizo diferentes cosas: -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"` +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"` -Ahora pensemos en que sucedió desde la perspectiva del efecto mismo: +Ahora pensemos en que sucedió desde la perspectiva del Efecto mismo: ```js useEffect(() => { - // Tu efecto se conectó a la sala especificado con el roomId + // Tu Efecto se conectó a la sala especificado con el roomId const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { @@ -194,17 +194,17 @@ Ahora pensemos en que sucedió desde la perspectiva del efecto mismo: Esta estructura de código podría inspirarte a ver lo que sucedió como una secuencia de períodos de tiempo no superpuestos: -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ó) +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ó) -Previamente, tu pensabas desde la perspectiva del componente. Cuando tu 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. +Previamente, tu pensabas desde la perspectiva del componente. Cuando tu 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. -**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 Effect será resistente a ser iniciado y detenido tantas veces como sea necesario.** +**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.** Esto podría recordarte cómo no pensar si un componente se está montando o actualizando cuando escribes la lógica de representación que crea JSX. Describes lo que debería estar en la pantalla y React [se encarga del resto.](/learn/reacting-to-input-with-state) -### Cómo React verifica que tu efecto pueda volver a sincronizarse {/*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*/} Aquí hay un ejemplo en vivo con el que puedes experimentar. Presiona "Abrir chat" para montar el componente `ChatRoom`: @@ -280,41 +280,41 @@ Observa que cuando el componente se monta por primera vez, ves tres registros: Los primeros dos registros son solo para desarrollo. En desarrollo, React siempre vuelve a montar cada componente una vez. -**React verifica que tu efecto puede volver a sincronizarse forzando lo 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) +**React verifica que tu Efecto puede volver a sincronizarse forzando lo 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) -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 se vuelve a sincronizarse. +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 se vuelve a sincronizarse. -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. +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. -### Cómo React conoce que es necesario volver a sincronizar el efecto {/*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*/} -Podría estarse 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) +Podría estarse 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 }) { // El props roomId puede cambiar con el tiempo useEffect(() => { - const connection = createConnection(serverUrl, roomId); // Este efecto lee roomId + const connection = createConnection(serverUrl, roomId); // Este Efecto lee roomId connection.connect(); return () => { connection.disconnect(); }; - }, [roomId]); // Entonces le dices a React que este efecto "depende de" roomId + }, [roomId]); // Entonces le dices a React que este Efecto "depende de" roomId // ... ``` Así es como funciona esto: 1. Sabías que `roomId` es un 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 especificó como la dependencia de su efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). +2. Sabías que tu Efecto lee `roomId` (porque lo usas para crear la conexión). +3. Es por esto que lo especificó como la dependencia de su Efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). -Cada vez que tu componente se vuelve a renderizar, React mirará la matriz de dependencias que has pasado. Si alguno de los valores en la matriz de dependencias es diferente del valor en el mismo lugar que pasaste durante el renderizado anterior, React volverá a sincronizar tu efecto. +Cada vez que tu componente se vuelve a renderizar, React mirará la matriz de dependencias que has pasado. Si alguno de los valores en la matriz de dependencias es diferente del valor en el mismo lugar que pasaste durante el renderizado anterior, React volverá a sincronizar tu Efecto. -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. +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. -### Cada efecto representa un proceso de sincronización separado {/*each-effect-represents-a-separate-synchronization-process*/} +### Cada Efecto representa un proceso de sincronización separado {/*each-effect-represents-a-separate-synchronization-process*/} -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í: +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 }) { } ``` -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: +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 }) { } ``` -**Cada efecto en tu código debe representar un proceso de sincronización separado e independiente.** +**Cada Efecto en tu código debe representar un proceso de sincronización separado e independiente.** -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. +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. ## Efectos "reaccionan" a valores reactivos {/*effects-react-to-reactive-values*/} -Tu efecto lee dos variables (`serverUrl` y `roomId`), pero solo especificaste `roomId` como una dependencia: +Tu Efecto lee dos variables (`serverUrl` y `roomId`), pero solo especificaste `roomId` como una dependencia: ```js {5,10} const serverUrl = 'https://localhost:1234'; @@ -382,17 +382,17 @@ function ChatRoom({ roomId }) { // 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); // Tu efecto lee props y estado + const connection = createConnection(serverUrl, roomId); // Tu Efecto lee props y estado connection.connect(); return () => { connection.disconnect(); }; - }, [roomId, serverUrl]); // Entonces le dices a react que este efecto "depende de" las props y el estado + }, [roomId, serverUrl]); // Entonces le dices a react que este Efecto "depende de" las props y el estado // ... } ``` -Al incluir `serverUrl` como una dependencia, te aseguras de que el efecto se vuelva a sincronizar después de que cambie. +Al incluir `serverUrl` como una dependencia, te aseguras de que el Efecto se vuelva a sincronizar después de que cambie. Intenta cambiar la sala de chat seleccionada o editar la URL del servidor en este _sandbox_: @@ -468,9 +468,9 @@ button { margin-left: 10px; } -Cuando sea que cambies un valor reactivo como `roomId` o `serverUrl`, el efecto se vuelve a conectar al servidor del chat. +Cuando sea que cambies un valor reactivo como `roomId` o `serverUrl`, el Efecto se vuelve a conectar al servidor del chat. -### Qué significa un efecto con dependencias vacías {/*what-an-effect-with-empty-dependencies-means*/} +### Qué significa un Efecto con dependencias vacías {/*what-an-effect-with-empty-dependencies-means*/} ¿Qué pasa si mueves tanto `serverUrl` como `roomId` fuera del componente? @@ -490,9 +490,9 @@ function ChatRoom() { } ``` -Ahora el código de tu efecto no usa *ningún* valor reactivo, por lo que sus dependencias pueden estar vacías (`[]`). +Ahora el código de tu Efecto no usa *ningún* valor reactivo, por lo que sus dependencias pueden estar vacías (`[]`). -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.) +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.) @@ -548,11 +548,11 @@ button { margin-left: 10px; } -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. +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. ### Todas las variables declaradas en el cuerpo del componente son reactivas {/*all-variables-declared-in-the-component-body-are-reactive*/} -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. +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. 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 la `serverUrl` en función del servidor seleccionado de las props y el servidor predeterminado: @@ -561,7 +561,7 @@ 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); // Tu efecto lee roomId y serverUrl + const connection = createConnection(serverUrl, roomId); // Tu Efecto lee roomId y serverUrl connection.connect(); return () => { connection.disconnect(); @@ -573,9 +573,9 @@ function ChatRoom({ roomId, selectedServerUrl }) { // roomId es reactivo 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. -**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.** +**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.** -En otras palabras, los efectos "reaccionan" a todos los valores del cuerpo del componente. +En otras palabras, los Efectos "reaccionan" a todos los valores del cuerpo del componente. @@ -583,9 +583,9 @@ En otras palabras, los efectos "reaccionan" a todos los valores del cuerpo del c Los valores mutables (incluidas las variables globales) no son reactivos. -**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) +**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) -**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. +**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. Como aprenderá a continuación en esta página, un linter verificará automáticamente estos problemas. @@ -593,7 +593,7 @@ Como aprenderá a continuación en esta página, un linter verificará automáti ### React verifica que especificaste cada valor reactivo como una dependencia {/*react-verifies-that-you-specified-every-reactive-value-as-a-dependency*/} -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: +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: @@ -667,9 +667,9 @@ button { margin-left: 10px; } -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. +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. -Para solucionar el error, sigue la sugerencia del linter de especificar `roomId` y `serverUrl` como dependencias de tu efecto: +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 es reactivo @@ -715,7 +715,7 @@ function ChatRoom() { } ``` -También puedes moverlos *dentro del efecto.* No se calculan durante el renderizado, por lo que no son reactivos: +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() { @@ -732,21 +732,21 @@ function ChatRoom() { } ``` -**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. +**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. -**No puedes "elegir" tus dependencias.** Tus dependencias deben incluir cada [valor reactivo](#todas-las-variables-declaradas-en-el-cuerpo-del-componente-son-reactivas) 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: +**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: -* **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.](#cada-efecto-representa-un-proceso-de-sincronización-separado) +* **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) -* **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) +* **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) -* **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) +* **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) -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. +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. -Si tienes una base de código existente, es posible que tengas algunos efectos que supriman el linter de esta manera: +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(() => { @@ -763,12 +763,12 @@ En la [siguiente](/learn/separating-events-from-effects) [página](/learn/removi - 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 *iniciar* y *detener*. -- 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). +- Cada Efecto tiene un ciclo de vida separado del componente circundante. +- Cada Efecto describe un proceso de sincronización separado que puede *iniciar* y *detener*. +- 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. +- 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. @@ -783,7 +783,7 @@ Sin embargo, hay un problema. Cada vez que escribes en el cuadro de entrada de m -Podrías necesitar agregar un _array_ de dependencias al efecto. ¿Qué dependencias deberían estar allí? +Podrías necesitar agregar un _array_ de dependencias al Efecto. ¿Qué dependencias deberían estar allí? @@ -860,7 +860,7 @@ button { margin-left: 10px; } -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. +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. @@ -937,13 +937,13 @@ button { margin-left: 10px; } #### Activar y desactivar la sincronización {/*switch-synchronization-on-and-off*/} -En este ejemplo, un efecto 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. +En este ejemplo, un Efecto 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. 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 si la casilla está marcada. -No puedes declarar un efecto condicionalmente. Sin embargo, ¡el código dentro del efecto puede usar condiciones! +No puedes declarar un Efecto condicionalmente. Sin embargo, ¡el código dentro del Efecto puede usar condiciones! @@ -1113,7 +1113,7 @@ body { -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. +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. @@ -1187,13 +1187,13 @@ body { -El problema con el codigo 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. +El problema con el codigo 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. -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` haya cambiado (y `handleMove` con él). Como React no volvió a sincronizar el efecto, el `handleMove` adjunto como oyente es la función `handleMove` creada durante la representación inicial. Durante la representación inicial, `canMove` era `true`, por lo que `handleMove` de la representación inicial siempre verá ese valor. +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` haya cambiado (y `handleMove` con él). Como React no volvió a sincronizar el Efecto, el `handleMove` adjunto como oyente es la función `handleMove` creada durante la representación inicial. Durante la representación inicial, `canMove` era `true`, por lo que `handleMove` de la representación inicial siempre verá ese valor. **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. -Puedes cambiar las dependencias del efecto a `[handleMove]`, pero como va a ser una función recién definida para cada representación, puedes eliminar por completo la matriz de dependencias. Entonces el efecto *se volverá a sincronizar* después de cada representación: +Puedes cambiar las dependencias del Efecto a `[handleMove]`, pero como va a ser una función recién definida para cada representación, puedes eliminar por completo la matriz de dependencias. Entonces el Efecto *se volverá a sincronizar* después de cada representación: @@ -1250,9 +1250,9 @@ body { -Esta solició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 representación. La resuscripción es rápida, pero aún así sería bueno evitar hacerlo tan a menudo. +Esta solició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 representación. La resuscripción es rápida, pero aún así sería bueno evitar hacerlo tan a menudo. -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`: +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`: @@ -1309,7 +1309,7 @@ body { -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. +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. Aprenerás un enfoque más general para este tipo de problema en [Separating Events from Effects.](/learn/separating-events-from-effects) @@ -1518,7 +1518,7 @@ label { display: block; margin-bottom: 10px; } -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 Effect podría volver a sincronizarse demasiado a menudo. Para evitar esto, puedes pasar `isEncrypted` en su lugar: +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: @@ -1613,7 +1613,7 @@ label { display: block; margin-bottom: 10px; } -En esta versión, el componente `App` pasa una prop booleana en lugar de una función. Dentro del Effect, 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 [Eliminación de dependencias de Effect.](/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 [Eliminación de dependencias del Efecto.](/learn/removing-effect-dependencies) @@ -1939,9 +1939,9 @@ label { display: block; margin-bottom: 10px; } -Este codigo es un poco repetitivo. Sin embargo, ¡no es una buena razón para combinarlo en un solo Effect! Si hicieras esto, tendrías que combinar las dependencias de ambos Effect en una sola lista, y luego cambiar el planeta volvería a buscar la lista de todos los planetas. Los Effects no son una herramienta para reutilizar código. +Este codigo 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 Effects no son una herramienta para reutilizar código. -En su lugar, para reducir la repetición, puede extraer algo de lógica en un Hook personalizado como `useSelectOptions` a continuación: +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: @@ -2102,7 +2102,7 @@ label { display: block; margin-bottom: 10px; } -Verifica el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks personalizados, ya sea escritos por usted o por la comunidad. Los Hooks personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Effect. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia. +Verifica el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks de React personalizados, ya sea escritos por usted o por la comunidad. Los Hooks de React personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Efecto. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks de React para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia. From 7db29dc47ae10ec4305364833d4bf03e99eef638 Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Fri, 2 Jun 2023 08:54:40 -0500 Subject: [PATCH 05/10] Update use Hooks instead of "Hooks de React" --- src/content/learn/lifecycle-of-reactive-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 1ce464b2f..de19f01c1 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -2102,7 +2102,7 @@ label { display: block; margin-bottom: 10px; } -Verifica el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks de React personalizados, ya sea escritos por usted o por la comunidad. Los Hooks de React personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Efecto. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks de React para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia. +Verifica el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks personalizados, ya sea escritos por usted o por la comunidad. Los Hooks personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Efecto. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia. From 66a38f707fc2e8eb35070e3ab2ae11ef999b4f29 Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Fri, 2 Jun 2023 08:59:10 -0500 Subject: [PATCH 06/10] Update references to "array" --- src/content/learn/lifecycle-of-reactive-effects.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index de19f01c1..3eb86afc6 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -308,7 +308,7 @@ Así es como funciona esto: 2. Sabías que tu Efecto lee `roomId` (porque lo usas para crear la conexión). 3. Es por esto que lo especificó como la dependencia de su Efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). -Cada vez que tu componente se vuelve a renderizar, React mirará la matriz de dependencias que has pasado. Si alguno de los valores en la matriz de dependencias es diferente del valor en el mismo lugar que pasaste durante el renderizado anterior, React volverá a sincronizar tu Efecto. +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. 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. @@ -860,7 +860,7 @@ button { margin-left: 10px; } -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. +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_. @@ -1193,7 +1193,7 @@ El autor del código original le ha "mentido" a React diciendo que el Efecto no **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. -Puedes cambiar las dependencias del Efecto a `[handleMove]`, pero como va a ser una función recién definida para cada representación, puedes eliminar por completo la matriz de dependencias. Entonces el Efecto *se volverá a sincronizar* después de cada representación: +Puedes cambiar las dependencias del Efecto a `[handleMove]`, pero como va a ser una función recién definida para cada representación, puedes eliminar por completo el _array_ de dependencias. Entonces el Efecto *se volverá a sincronizar* después de cada representación: From a967f5f2644bb16edbcb3c8d18bcc00e46b5dd26 Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Wed, 14 Jun 2023 10:08:42 -0500 Subject: [PATCH 07/10] Update lifecycle-of-reactive-effects.md --- src/content/learn/lifecycle-of-reactive-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 3eb86afc6..5f6754f25 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -1117,7 +1117,7 @@ En ambos casos, `canMove` es una variable reactiva que lees dentro del Efecto. P -#### Ivestiga un error de valor absoluto {/*investigate-a-stale-value-bug*/} +#### Ivestiga un error de valor absoluto {/*investigate-a-stale-value-bug*/} 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`. From be975f47a5a33724c052c342477c1ffe00ee864f Mon Sep 17 00:00:00 2001 From: Meiyer Jaimes Date: Wed, 14 Jun 2023 10:42:27 -0500 Subject: [PATCH 08/10] Fix DeepDive translate --- src/content/learn/lifecycle-of-reactive-effects.md | 2 +- src/sidebarLearn.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 5f6754f25..5c29a9788 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -579,7 +579,7 @@ En otras palabras, los Efectos "reaccionan" a todos los valores del cuerpo del c -### ¿Pueden los valores globales o mutables ser dependencias? {/*can-global-or-mutable-values-be-dependencies*/} +#### ¿Pueden los valores globales o mutables ser dependencias? {/*can-global-or-mutable-values-be-dependencies*/} Los valores mutables (incluidas las variables globales) no son reactivos. diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index 0090517b1..c0f7316f0 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -177,7 +177,7 @@ "path": "/learn/you-might-not-need-an-effect" }, { - "title": "Ciclo de vida de los efectos reactivos", + "title": "Ciclo de vida de los Efectos reactivos", "path": "/learn/lifecycle-of-reactive-effects" }, { From 97d546da88d380c42e089099922c023257aa42ea Mon Sep 17 00:00:00 2001 From: Rainer Martinez Date: Wed, 14 Jun 2023 23:05:04 -0400 Subject: [PATCH 09/10] copy editing --- .../learn/lifecycle-of-reactive-effects.md | 134 +++++++++--------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 5c29a9788..184e1cc76 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -4,7 +4,7 @@ title: 'Ciclo de vida de los Efectos reactivos' -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: para 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 los últimos _props_ y estado. +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. @@ -17,7 +17,7 @@ Los Efectos tienen un diferente ciclo de vida al de los componentes. Los compone - 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á de acuerdo con el _linter_ +- Qué hacer cuanto no estás de acuerdo con el _linter_ @@ -26,12 +26,12 @@ Los Efectos tienen un diferente ciclo de vida al de los componentes. Los compone Cada componente de React pasa por el mismo ciclo de vida: - 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 _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. -**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 su código cambia, la sincronización tendrá que suceder mas o menos a menudo. +**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. -Para ilustrar este punto, considera este Efecto que conecta su componente a un servidor de chat: +Para ilustrar este punto, considera este Efecto que conecta tu componente a un servidor de chat: ```js const serverUrl = 'https://localhost:1234'; @@ -84,7 +84,7 @@ Algunos Efectos no devuelven una función de limpieza en absoluto. [Más a menud ### Por qué la sincronización puede necesitar suceder mas de una vez {/*why-synchronization-may-need-to-happen-more-than-once*/} -Imagina que este componente `ChatRoom` recibe un `roomId` _prop_ 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"`: +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'; @@ -95,7 +95,7 @@ function ChatRoom({ roomId /* "general" */ }) { } ``` -Después que se muestre el _UI_, React ejecutará el Efecto para **iniciar la sincronización.** Se conecta a la sala `"general"`: +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" */ }) { @@ -111,7 +111,7 @@ function ChatRoom({ roomId /* "general" */ }) { Hasta ahora, todo bien. -Luego, el usuario selecciona una sala diferente en el menú desplegable (por ejemplo, `"trave"`). Primero, React actualizará el _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" */ }) { @@ -120,45 +120,45 @@ function ChatRoom({ roomId /* "travel" */ }) { } ``` -Piensa en que debería suceder luego. El usuario ve que `"travel"` es la sala de chat en el _UI_. Sin embargo, el Efecto que se ejecutó la última vez aun está conectada a la sala `"general"`. **El `"roomId"` _prop_ ha cambiado, asi que lo que el Efecto hizo en ese entonces (conectarse a la sala `"general"`) ya no coincide con el _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.** En este punto, deseas que React haga dos cosas: -1. Detener la sincronización con el antiguo `roomId`(desconectarse de la sala `"general"`) -2. Iniciar la sincronización con el nuevo `roomId`(conectarse a la sala `"travel"`) +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"`) -**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. +**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. ### Cómo React vuelve a sincronizar tu Efecto {/*how-react-re-synchronizes-your-effect*/} -Recuerda que tu componente `ChatRoom` había recibido un nuevo valor para su `roomId` _prop_. Solía ser `"general"`, y ahora es `"travel"`. React necesita volver a sincronizar tu Efecto para volver a conectar a una sala diferente. +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. 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); // Conectar a la sala "general" + const connection = createConnection(serverUrl, roomId); // Se conecta a la sala "general" connection.connect(); return () => { - connection.disconnect(); // Desconectar de la sala "general" + connection.disconnect(); // Se desconecta de la sala "general" }; // ... ``` -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 es eventualmente llamado también): +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); // Conecta a la sala "travel" + const connection = createConnection(serverUrl, roomId); // Se conecta a la sala "travel" connection.connect(); // ... ``` -Gracias a esto, ahora estás conectado a la misma sala que el usuario eligió en el UI. ¡Desastre evitado! +Gracias a esto, ahora estás conectado a la misma sala que el usuario eligió en la UI. ¡Desastre evitado! -Cada vez que su 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 el nuevo `roomId` _prop_ (conectándose a la sala `"music"`). +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"`). 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"`. @@ -166,10 +166,10 @@ Finalmente, cuando el usuario vaya a una pantalla diferente, `ChatRoom` se desmo Recapitulemos todo lo que sucedió desde la perspectiva del componente `ChatRoom`: -1. `ChatRoom` montado con `roomId` establecido en `"general"` -2. `ChatRoom` actualizado con `roomId` establecido en `"travel"` -3. `ChatRoom` actualizado con `roomId` establecido en `"music"` -4. `ChatRoom` desmontado +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ó Durante cada uno de estos puntos en el ciclo de vida del componente, tu Efecto hizo diferentes cosas: @@ -178,11 +178,11 @@ Durante cada uno de estos puntos en el ciclo de vida del componente, tu Efecto h 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"` -Ahora pensemos en que sucedió desde la perspectiva del Efecto mismo: +Ahora pensemos qué sucedió desde la perspectiva del Efecto mismo: ```js useEffect(() => { - // Tu Efecto se conectó a la sala especificado con el roomId + // Tu Efecto se conectó a la sala especificada con el roomId... const connection = createConnection(serverUrl, roomId); connection.connect(); return () => { @@ -198,11 +198,11 @@ Esta estructura de código podría inspirarte a ver lo que sucedió como una sec 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ó) -Previamente, tu pensabas desde la perspectiva del componente. Cuando tu 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. +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. **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.** -Esto podría recordarte cómo no pensar si un componente se está montando o actualizando cuando escribes la lógica de representación que crea JSX. Describes lo que debería estar en la pantalla y React [se encarga del resto.](/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) ### Cómo React verifica que tu Efecto pueda volver a sincronizarse {/*how-react-verifies-that-your-effect-can-re-synchronize*/} @@ -274,24 +274,24 @@ button { margin-left: 10px; } Observa que cuando el componente se monta por primera vez, ves tres registros: -1. `✅ Conectando a la sala "general" en https://localhost:1234...` *(development-only)* -1. `❌ Desconectando de "general" en https://localhost:1234.` *(development-only)* +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...` Los primeros dos registros son solo para desarrollo. En desarrollo, React siempre vuelve a montar cada componente una vez. -**React verifica que tu Efecto puede volver a sincronizarse forzando lo 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) +**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) -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 se vuelve a sincronizarse. +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. 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. ### Cómo React conoce que es necesario volver a sincronizar el Efecto {/*how-react-knows-that-it-needs-to-re-synchronize-the-effect*/} -Podría estarse 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) +Podría 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 }) { // El props roomId puede cambiar con el tiempo +function ChatRoom({ roomId }) { // La prop roomId puede cambiar con el tiempo useEffect(() => { const connection = createConnection(serverUrl, roomId); // Este Efecto lee roomId connection.connect(); @@ -304,9 +304,9 @@ function ChatRoom({ roomId }) { // El props roomId puede cambiar con el tiempo Así es como funciona esto: -1. Sabías que `roomId` es un prop, lo que significa que puede cambiar con el tiempo. +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 especificó como la dependencia de su Efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). +3. Es por esto que lo especificaste como la dependencia de tu Efecto. (para que se vuelva a sincronizar cuando `roomId` cambie). 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. @@ -350,7 +350,7 @@ function ChatRoom({ roomId }) { 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. -## Efectos "reaccionan" a valores reactivos {/*effects-react-to-reactive-values*/} +## Los Efectos "reaccionan" a valores reactivos {/*effects-react-to-reactive-values*/} Tu Efecto lee dos variables (`serverUrl` y `roomId`), pero solo especificaste `roomId` como una dependencia: @@ -371,14 +371,14 @@ function ChatRoom({ roomId }) { ¿Por qué no se especifica `serverUrl` como una dependencia? -Esto es porque el `serverUrl` nunca cambia debido a un re-renderizado. 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! +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! -Por otro lado, `roomId` puede ser diferente en un re-renderizado. **Los 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.** +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.** 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 cambian con el tiempo +function ChatRoom({ roomId }) { // Las props cambian con el tiempo const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // El estado puede cambiar con el tiempo useEffect(() => { @@ -387,7 +387,7 @@ function ChatRoom({ roomId }) { // Props cambian con el tiempo return () => { connection.disconnect(); }; - }, [roomId, serverUrl]); // Entonces le dices a react que este Efecto "depende de" las props y el estado + }, [roomId, serverUrl]); // Entonces le dices a React que este Efecto "depende de" las props y el estado // ... } ``` @@ -449,7 +449,7 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // Una implementación real A real implementation en realidad se conectaría al servidor + // Una implementación real en realidad se conectaría al servidor return { connect() { console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); @@ -468,9 +468,9 @@ button { margin-left: 10px; } -Cuando sea que cambies un valor reactivo como `roomId` o `serverUrl`, el Efecto se vuelve a conectar al servidor del chat. +Cada vez que cambies un valor reactivo como `roomId` o `serverUrl`, el Efecto se vuelve a conectar al servidor del chat. -### Qué significa un Efecto con dependencias vacías {/*what-an-effect-with-empty-dependencies-means*/} +### ¿Qué significa un Efecto con dependencias vacías? {/*what-an-effect-with-empty-dependencies-means*/} ¿Qué pasa si mueves tanto `serverUrl` como `roomId` fuera del componente? @@ -554,7 +554,7 @@ Sin embargo, si [piensas desde la perspectiva del Efecto,](#thinking-from-the-ef 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. -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 la `serverUrl` en función del servidor seleccionado de las props y el servidor predeterminado: +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 es reactivo @@ -587,7 +587,7 @@ Los valores mutables (incluidas las variables globales) no son reactivos. **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. -Como aprenderá a continuación en esta página, un linter verificará automáticamente estos problemas. +Como aprenderás a continuación en esta página, un linter verificará automáticamente estos problemas. @@ -648,7 +648,7 @@ export default function App() { ```js chat.js export function createConnection(serverUrl, roomId) { - // Una implementación real en realidad conectaría al servidor + // Una implementación real en realidad se conectaría al servidor return { connect() { console.log('✅ Conectando a la sala "' + roomId + '" en ' + serverUrl + '...'); @@ -693,7 +693,7 @@ En algunos casos, React *sabe* que un valor nunca cambia aunque se declare dentr -### Qué hacer cuando no quieres volver a sincronizar {/*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*/} En los ejemplos previos, has arreglado el error del linter enumerando `roomId` y `serverUrl` como dependencias. @@ -738,7 +738,7 @@ function ChatRoom() { * **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) -* **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) +* **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) * **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) @@ -764,7 +764,7 @@ En la [siguiente](/learn/separating-events-from-effects) [página](/learn/removi - 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 *iniciar* y *detener*. +- 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. @@ -937,9 +937,9 @@ button { margin-left: 10px; } #### Activar y desactivar la sincronización {/*switch-synchronization-on-and-off*/} -En este ejemplo, un Efecto 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. +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. -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 si la casilla está marcada. +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. @@ -1117,7 +1117,7 @@ En ambos casos, `canMove` es una variable reactiva que lees dentro del Efecto. P -#### Ivestiga un error de valor absoluto {/*investigate-a-stale-value-bug*/} +#### Investiga un error de valor obsoleto {/*investigate-a-stale-value-bug*/} 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`. @@ -1187,13 +1187,13 @@ body { -El problema con el codigo 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. +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. -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` haya cambiado (y `handleMove` con él). Como React no volvió a sincronizar el Efecto, el `handleMove` adjunto como oyente es la función `handleMove` creada durante la representación inicial. Durante la representación inicial, `canMove` era `true`, por lo que `handleMove` de la representación inicial siempre verá ese valor. +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. **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. -Puedes cambiar las dependencias del Efecto a `[handleMove]`, pero como va a ser una función recién definida para cada representación, puedes eliminar por completo el _array_ de dependencias. Entonces el Efecto *se volverá a sincronizar* después de cada representación: +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: @@ -1250,7 +1250,7 @@ body { -Esta solició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 representación. La resuscripción es rápida, pero aún así sería bueno evitar hacerlo tan a menudo. +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. 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`: @@ -1311,15 +1311,15 @@ body { 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. -Aprenerás un enfoque más general para este tipo de problema en [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) #### Solucionar un cambio de conexión {/*fix-a-connection-switch*/} -En este ejemplo, el servicio de chat en `chat.js` expone dos API 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`. +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`. -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 cambiar el checkbox *también* haga que el chat se reconecte. +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. @@ -1613,7 +1613,7 @@ label { display: block; margin-bottom: 10px; } -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 [Eliminación de dependencias del Efecto.](/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) @@ -1627,7 +1627,7 @@ Si lo haces bien, seleccionar un planeta debería rellenar la lista de lugares. -Si tienes dos procesos de sincronización independientes, necesitas escribir dos Effects separados. +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('Obtener una lista de planetas.'); + console.log('Se obtuvo una lista de planetas.'); setPlanetList(result); - setPlanetId(result[0].id); // Seleccione el primer planeta + setPlanetId(result[0].id); // Se selecciona el primer planeta } }); return () => { @@ -1778,7 +1778,7 @@ Hay dos procesos de sincronización independientes: - 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. -Por eso tiene sentido describirlos como dos Effects separados. Aquí tienes un ejemplo de cómo podrías hacerlo: +Por eso tiene sentido describirlos como dos Efectos separados. Aquí tienes un ejemplo de cómo podrías hacerlo: @@ -1797,7 +1797,7 @@ export default function Page() { let ignore = false; fetchData('/planets').then(result => { if (!ignore) { - console.log('Obtener una lista de planetas.'); + console.log('Se obtuvo una lista de planetas.'); setPlanetList(result); setPlanetId(result[0].id); // Selecciona el primer planeta } @@ -1939,7 +1939,7 @@ label { display: block; margin-bottom: 10px; } -Este codigo 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 Effects no son una herramienta para reutilizar código. +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. 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: @@ -2102,7 +2102,7 @@ label { display: block; margin-bottom: 10px; } -Verifica el tab `useSelectOptions.js` en el sandbox para ver cómo funciona. Idealmente, la mayoría de los Effects en su aplicación eventualmente deberían reemplazarse por Hooks personalizados, ya sea escritos por usted o por la comunidad. Los Hooks personalizados ocultan la lógica de sincronización, por lo que el componente de llamada no conoce el Efecto. A medida que siga trabajando en su aplicación, desarrollará una paleta de Hooks para elegir, y eventualmente no necesitará escribir Effects en sus componentes con mucha frecuencia. +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. From ea65921cd66fe152e83371bf8297489a0ed7f72b Mon Sep 17 00:00:00 2001 From: Rainer Martinez Date: Wed, 14 Jun 2023 23:08:26 -0400 Subject: [PATCH 10/10] Update lifecycle-of-reactive-effects.md --- src/content/learn/lifecycle-of-reactive-effects.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 184e1cc76..a4a767dbc 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -288,7 +288,7 @@ Sin embargo, también hay casos más inusuales en los que es necesario que vuelv ### Cómo React conoce que es necesario volver a sincronizar el Efecto {/*how-react-knows-that-it-needs-to-re-synchronize-the-effect*/} -Podría 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) +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 }) { // La prop roomId puede cambiar con el tiempo