diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md
index 3dc9a75f0..833f63c72 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 dos Efeitos Reativos'
---
-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.
+Os Efeitos têm um ciclo de vida diferente dos componentes. Componentes podem montar, atualizar ou desmontar. Um Efeito pode fazer apenas duas coisas: começar a sincronizar algo e, mais tarde, parar de sincronizá-lo. Este ciclo pode acontecer várias vezes se o seu Efeito depender de props e estados que mudam ao longo do tempo. O React fornece uma regra de lint para verificar se você especificou corretamente as dependências do seu Efeito. Isso mantém seu Efeito sincronizado com as últimas props e 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
+- Como o ciclo de vida de um Efeito é diferente do ciclo de vida de um componente
+- Como pensar sobre cada Efeito individualmente em isolamento
+- Quando seu Efeito precisa re-sincronizar e por quê
+- Como as dependências do seu Efeito são determinadas
+- O que significa um valor ser reativo
+- O que significa um array de dependências vazio
+- Como o React verifica se suas dependências estão corretas com um linter
+- O que fazer quando você discorda do linter
-## The lifecycle of an Effect {/*the-lifecycle-of-an-effect*/}
+## O ciclo de vida de um Efeito {/*the-lifecycle-of-an-effect*/}
-Every React component goes through the same lifecycle:
+Todo componente React passa pelo mesmo 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.
+- Um componente _monta_ quando é adicionado à tela.
+- Um componente _atualiza_ quando recebe novas props ou estado, geralmente em resposta a uma interação.
+- Um componente _desmonta_ quando é removido da tela.
-**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.
+**É uma boa maneira de pensar sobre componentes, mas _não_ sobre Efeitos.** Em vez disso, tente pensar em cada Efeito de forma independente do ciclo de vida do seu componente. Um Efeito descreve como [sincronizar um sistema externo](/learn/synchronizing-with-effects) com as props e estado atuais. À medida que seu código muda, a sincronização precisará acontecer mais ou menos frequentemente.
-To illustrate this point, consider this Effect connecting your component to a chat server:
+Para ilustrar este ponto, considere este Efeito conectando seu componente a um 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:**
+O corpo do seu Efeito especifica como **começar a sincronizar:**
```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:**
+A função de limpeza retornada pelo seu Efeito especifica como **parar de sincronizar:**
```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, você pode pensar que o React **começaria a sincronizar** quando seu componente monta e **pararia de sincronizar** quando seu componente desmonta. No entanto, este não é o fim da história! Às vezes, pode ser necessário **começar e parar de sincronizar várias vezes** enquanto o componente permanece montado.
-Let's look at _why_ this is necessary, _when_ it happens, and _how_ you can control this behavior.
+Vamos analisar _por que_ isso é necessário, _quando_ isso acontece e _como_ você pode controlar esse comportamento.
-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.
+Alguns Efeitos não retornam uma função de limpeza. [Mais frequentemente do que não,](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) você vai querer retornar uma--mas se não o fizer, o React se comportará como se você tivesse retornado uma função de limpeza vazia.
-### Why synchronization may need to happen more than once {/*why-synchronization-may-need-to-happen-more-than-once*/}
+### Por que a sincronização pode precisar acontecer mais de uma 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:
+Imagine que este componente `ChatRoom` recebe uma prop `roomId` que o usuário escolhe em um dropdown. Vamos supor que inicialmente o usuário escolha a sala `"general"` como o `roomId`. Seu aplicativo exibe a sala de chat `"general"`:
```js {3}
const serverUrl = 'https://localhost:1234';
function ChatRoom({ roomId /* "general" */ }) {
// ...
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à sala {roomId}!
;
}
```
-After the UI is displayed, React will run your Effect to **start synchronizing.** It connects to the `"general"` room:
+Depois que a UI é exibida, o React executará seu Efeito para **começar a sincronizar.** Ele se conecta à 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-se à sala "general"
connection.connect();
return () => {
- connection.disconnect(); // Disconnects from the "general" room
+ connection.disconnect(); // Desconecta da sala "general"
};
}, [roomId]);
// ...
```
-So far, so good.
+Até aqui, tudo certo.
-Later, the user picks a different room in the dropdown (for example, `"travel"`). First, React will update the UI:
+Mais tarde, o usuário escolhe uma sala diferente no dropdown (por exemplo, `"travel"`). Primeiro, o React atualizará a UI:
```js {1}
function ChatRoom({ roomId /* "travel" */ }) {
// ...
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à 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.**
+Pense sobre o que deve acontecer a seguir. O usuário vê que `"travel"` é a sala de chat selecionada na UI. No entanto, o Efeito que foi executado da última vez ainda está conectado à sala `"general"`. **A prop `roomId` mudou, então o que seu Efeito fez na última vez (conectando-se à sala `"general"`) não corresponde mais à UI.**
-At this point, you want React to do two things:
+Neste ponto, você gostaria que o React fizesse duas coisas:
-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. Parar de sincronizar com o antigo `roomId` (desconectar da sala `"general"`)
+2. Começar a sincronizar com o novo `roomId` (conectar à 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.
+**Felizmente, você já ensinou ao React como fazer ambas essas coisas!** O corpo do seu Efeito especifica como começar a sincronizar, e sua função de limpeza especifica como parar de sincronizar. Tudo o que o React precisa fazer agora é chamá-los na ordem correta e com as props e estado corretos. Vamos ver como exatamente isso acontece.
-### How React re-synchronizes your Effect {/*how-react-re-synchronizes-your-effect*/}
+### Como o React re-sincroniza seu Efeito {/*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.
+Lembre-se de que seu componente `ChatRoom` recebeu um novo valor para sua prop `roomId`. Antes, era `"general"` e agora é `"travel"`. O React precisa re-sincronizar seu Efeito para reconectá-lo a uma 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 **parar de sincronizar,** o React chamará a função de limpeza que seu Efeito retornou após se conectar à sala `"general"`. Como `roomId` era `"general"`, a função de limpeza desconecta da sala `"general"`:
```js {6}
function ChatRoom({ roomId /* "general" */ }) {
useEffect(() => {
- const connection = createConnection(serverUrl, roomId); // Connects to the "general" room
+ const connection = createConnection(serverUrl, roomId); // Conecta-se à sala "general"
connection.connect();
return () => {
- connection.disconnect(); // Disconnects from the "general" room
+ connection.disconnect(); // Desconecta da 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):
+Depois, o React executará o Efeito que você forneceu durante esta renderização. Desta vez, `roomId` é `"travel"` então ele **começará a sincronizar** com a sala de chat `"travel"` (até que sua função de limpeza seja eventualmente chamada também):
```js {3,4}
function ChatRoom({ roomId /* "travel" */ }) {
useEffect(() => {
- const connection = createConnection(serverUrl, roomId); // Connects to the "travel" room
+ const connection = createConnection(serverUrl, roomId); // Conecta-se à sala "travel"
connection.connect();
// ...
```
-Thanks to this, you're now connected to the same room that the user chose in the UI. Disaster averted!
+Graças a isso, agora você está conectado à mesma sala que o usuário escolheu na 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).
+Toda vez que seu componente re-renderiza com um `roomId` diferente, seu Efeito será re-sincronizado. Por exemplo, vamos supor que o usuário muda `roomId` de `"travel"` para `"music"`. O React novamente **parará de sincronizar** seu Efeito chamando sua função de limpeza (desconectando-o da sala `"travel"`). Então, ele **começará a sincronizar** novamente executando seu corpo com a nova prop `roomId` (conectando-o à 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, quando o usuário vai para uma tela diferente, `ChatRoom` desmonta. Agora não há necessidade de permanecer conectado. O React **parará de sincronizar** seu Efeito uma última vez e desconectará você da sala de chat `"music"`.
-### Thinking from the Effect's perspective {/*thinking-from-the-effects-perspective*/}
+### Pensando da perspectiva do Efeito {/*thinking-from-the-effects-perspective*/}
-Let's recap everything that's happened from the `ChatRoom` component's perspective:
+Vamos recapitular tudo o que aconteceu da perspectiva do 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` montou com `roomId` definido como `"general"`
+1. `ChatRoom` atualizou com `roomId` definido como `"travel"`
+1. `ChatRoom` atualizou com `roomId` definido como `"music"`
+1. `ChatRoom` desmontou
-During each of these points in the component's lifecycle, your Effect did different things:
+Durante cada um desses pontos no ciclo de vida do componente, seu Efeito fez coisas diferentes:
-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. Seu Efeito conectou-se à sala `"general"`
+1. Seu Efeito desconectou da sala `"general"` e conectou na sala `"travel"`
+1. Seu Efeito desconectou da sala `"travel"` e conectou na sala `"music"`
+1. Seu Efeito desconectou da sala `"music"`
-Now let's think about what happened from the perspective of the Effect itself:
+Agora vamos pensar sobre o que aconteceu da perspectiva do próprio Efeito:
```js
useEffect(() => {
- // Your Effect connected to the room specified with roomId...
+ // Seu Efeito conectou-se à sala especificada com roomId...
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
- // ...until it disconnected
+ // ...até que se desconectou
connection.disconnect();
};
}, [roomId]);
```
-This code's structure might inspire you to see what happened as a sequence of non-overlapping time periods:
+A estrutura desse código pode inspirá-lo a ver o que aconteceu como uma sequência de períodos de tempo não sobrepostos:
-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. Seu Efeito conectou-se à sala `"general"` (até se desconectar)
+1. Seu Efeito conectou-se à sala `"travel"` (até se desconectar)
+1. Seu Efeito conectou-se à sala `"music"` (até se desconectar)
-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.
+Anteriormente, você estava pensando da perspectiva do componente. Quando você olhou da perspectiva do componente, era tentador pensar nos Efeitos como "callbacks" ou "eventos de ciclo de vida" que disparam em um momento específico, como "após uma renderização" ou "antes de desmontar". Essa forma de pensar fica complicada muito rapidamente, então é melhor evitar.
-**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.**
+**Em vez disso, concentre-se sempre em um único ciclo de início/parada de cada vez. Não deve importar se um componente está montando, atualizando ou desmontando. Tudo o que você precisa fazer é descrever como iniciar a sincronização e como parar. Se você fizer isso bem, seu Efeito resistirá a ser iniciado e interrompido quantas vezes forem necessárias.**
-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)
+Isso pode lembrá-lo de como você não pensa se um componente está montando ou atualizando quando escreve a lógica de renderização que cria JSX. Você descreve o que deve estar na tela, e o React [decide o 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*/}
+### Como o React verifica que seu Efeito pode re-sincronizar {/*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:
+Aqui está um exemplo ao vivo com o qual você pode brincar. Pressione "Abrir chat" para montar o componente `ChatRoom`:
@@ -222,7 +222,7 @@ function ChatRoom({ roomId }) {
connection.connect();
return () => connection.disconnect();
}, [roomId]);
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à sala {roomId}!
;
}
export default function App() {
@@ -231,7 +231,7 @@ export default function App() {
return (
<>
{show && }
{show && }
@@ -253,13 +253,13 @@ export default function App() {
```js src/chat.js
export function createConnection(serverUrl, roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...');
+ console.log('✅ Conectando à sala "' + roomId + '" em ' + serverUrl + '...');
},
disconnect() {
- console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl);
+ console.log('❌ Desconectado da sala "' + roomId + '" em ' + serverUrl);
}
};
}
@@ -272,49 +272,49 @@ button { margin-left: 10px; }
-Notice that when the component mounts for the first time, you see three logs:
+Perceba que quando o componente monta pela primeira vez, você vê três logs:
-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 à sala "general" em https://localhost:1234...` *(somente no desenvolvimento)*
+1. `❌ Desconectado da sala "general" em https://localhost:1234.` *(somente no desenvolvimento)*
+1. `✅ Conectando à sala "general" em https://localhost:1234...`
-The first two logs are development-only. In development, React always remounts each component once.
+Os dois primeiros logs são somente para desenvolvimento. No desenvolvimento, o React sempre desmonta cada componente uma 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)
+**O React verifica que seu Efeito pode re-sincronizar forçando-o a fazer isso imediatamente em desenvolvimento.** Isso pode lembrá-lo de abrir uma porta e fechá-la uma vez a mais para verificar se a fechadura da porta funciona. O React inicia e para seu Efeito uma vez a mais no desenvolvimento para verificar [se você implementou a limpeza bem.](/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.
+A principal razão pela qual seu Efeito re-sincronizará na prática é se alguns dos dados que ele usa mudaram. No sandbox acima, altere a sala de chat selecionada. Perceba que, quando o `roomId` muda, seu Efeito re-sincroniza.
-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.
+No entanto, há também casos mais incomuns em que a re-sincronização é necessária. Por exemplo, tente editar o `serverUrl` no sandbox acima enquanto o chat está aberto. Perceba como o Efeito re-sincroniza em resposta às suas edições ao código. No futuro, o React pode adicionar mais recursos que dependem da re-sincronização.
-### How React knows that it needs to re-synchronize the Effect {/*how-react-knows-that-it-needs-to-re-synchronize-the-effect*/}
+### Como o React sabe que precisa re-sincronizar o Efeito {/*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)
+Você pode estar se perguntando como o React sabia que seu Efeito precisava re-sincronizar após as mudanças no `roomId`. É porque *você disse ao React* que seu código depende de `roomId` ao incluí-lo na [lista de dependências:](/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 }) { // A prop roomId pode mudar ao longo do tempo
useEffect(() => {
- const connection = createConnection(serverUrl, roomId); // This Effect reads roomId
+ const connection = createConnection(serverUrl, roomId); // Este Efeito lê roomId
connection.connect();
return () => {
connection.disconnect();
};
- }, [roomId]); // So you tell React that this Effect "depends on" roomId
+ }, [roomId]); // Então você diz ao React que este Efeito "depende de" roomId
// ...
```
-Here's how this works:
+Aqui está como isso funciona:
-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. Você sabia que `roomId` é uma prop, o que significa que pode mudar ao longo do tempo.
+2. Você sabia que seu Efeito lê `roomId` (então sua lógica depende de um valor que pode mudar mais tarde).
+3. É por isso que você especificou isso como uma dependência do seu Efeito (para que ele re-sincronize quando `roomId` muda).
-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.
+Toda vez que seu componente re-renderiza, o React olhará para o array de dependências que você passou. Se algum dos valores no array for diferente do valor no mesmo lugar que você passou durante a renderização anterior, o React re-sincronizará seu Efeito.
-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 exemplo, se você passou `["general"]` durante a renderização inicial e depois passou `["travel"]` durante a próxima renderização, o React comparará `"general"` e `"travel"`. Esses são valores diferentes (comparados com [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), então o React re-sincronizará seu Efeito. Por outro lado, se seu componente re-renderiza, mas `roomId` não mudou, seu Efeito permanecerá conectado à mesma sala.
-### Each Effect represents a separate synchronization process {/*each-effect-represents-a-separate-synchronization-process*/}
+### Cada Efeito representa um processo de sincronização 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:
+Resista à tentação de adicionar lógica não relacionada ao seu Efeito apenas porque essa lógica precisa ser executada ao mesmo tempo que um Efeito que você já escreveu. Por exemplo, digamos que você queira registrar um evento de análise quando o usuário visita a sala. Você já tem um Efeito que depende de `roomId`, então pode sentir a tentação de adicionar a chamada de análise lá:
```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:
+Mas imagine que você mais tarde adicione outra dependência a este Efeito que precisa restabelecer a conexão. Se este Efeito re-sincronizar, ele também chamará `logVisit(roomId)` para a mesma sala, o que você não pretendia. Registrar a visita **é um processo separado** de conectar. Escreva-os como dois Efeitos 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 Efeito no seu código deve representar um processo de sincronização separado e independente.**
-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.
+No exemplo acima, excluir um Efeito não quebraria a lógica do outro Efeito. Este é um bom indicativo de que eles sincronizam coisas diferentes, portanto, faz sentido dividi-los. Por outro lado, se você dividir um pedaço coeso de lógica em Efeitos separados, o código pode parecer "mais limpo", mas será [mais difícil de manter.](/learn/you-might-not-need-an-effect#chains-of-computations) Por isso, você deve pensar se os processos são iguais ou separados, não se o código parece mais limpo.
-## Effects "react" to reactive values {/*effects-react-to-reactive-values*/}
+## Efeitos "reagem" a valores reativos {/*effects-react-to-reactive-values*/}
-Your Effect reads two variables (`serverUrl` and `roomId`), but you only specified `roomId` as a dependency:
+Seu Efeito lê duas variáveis (`serverUrl` e `roomId`), mas você especificou apenas `roomId` como uma dependência:
```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 que `serverUrl` não precisa ser uma dependência?
-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!
+Isso acontece porque o `serverUrl` nunca muda devido a uma re-renderização. Ele é sempre o mesmo, não importa quantas vezes o componente é re-renderizado e por quê. Como o `serverUrl` nunca muda, não faria sentido especificá-lo como uma dependência. Afinal, as dependências só fazem algo quando mudam ao longo do tempo!
-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 outro lado, `roomId` pode ser diferente em uma re-renderização. **Props, estados e outros valores declarados dentro do componente são _reativos_ porque são calculados durante a renderização e participam do fluxo de dados do React.**
-If `serverUrl` was a state variable, it would be reactive. Reactive values must be included in dependencies:
+Se `serverUrl` fosse uma variável de estado, seria reativa. Valores reativos devem ser incluídos nas dependências:
```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 mudam ao longo do tempo
+ const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // O estado pode mudar ao longo do tempo
useEffect(() => {
- const connection = createConnection(serverUrl, roomId); // Your Effect reads props and state
+ const connection = createConnection(serverUrl, roomId); // Seu Efeito lê props e estado
connection.connect();
return () => {
connection.disconnect();
};
- }, [roomId, serverUrl]); // So you tell React that this Effect "depends on" on props and state
+ }, [roomId, serverUrl]); // Então você diz ao React que este Efeito "depende de" props e estado
// ...
}
```
-By including `serverUrl` as a dependency, you ensure that the Effect re-synchronizes after it changes.
+Incluindo `serverUrl` como uma dependência, você garante que o Efeito re-sincroniza após mudar.
-Try changing the selected chat room or edit the server URL in this sandbox:
+Tente mudar a sala de chat selecionada ou editar a URL do servidor neste sandbox:
@@ -414,13 +414,13 @@ function ChatRoom({ roomId }) {
return (
<>
-
Welcome to the {roomId} room!
+
Bem-vindo à sala {roomId}!
>
);
}
@@ -430,7 +430,7 @@ export default function App() {
return (
<>
-Whenever you change a reactive value like `roomId` or `serverUrl`, the Effect re-connects to the chat server.
+Toda vez que você mudar um valor reativo como `roomId` ou `serverUrl`, o Efeito reconecta-se ao servidor de chat.
-### What an Effect with empty dependencies means {/*what-an-effect-with-empty-dependencies-means*/}
+### O que significa um Efeito com dependências vazias {/*what-an-effect-with-empty-dependencies-means*/}
-What happens if you move both `serverUrl` and `roomId` outside the component?
+O que acontece se você mover tanto `serverUrl` quanto `roomId` para fora do componente?
```js {1,2}
const serverUrl = 'https://localhost:1234';
@@ -485,15 +485,14 @@ function ChatRoom() {
return () => {
connection.disconnect();
};
- }, []); // ✅ All dependencies declared
+ }, []); // ✅ Todas as dependências declaradas
// ...
}
```
-Now your Effect's code does not use *any* reactive values, so its dependencies can be empty (`[]`).
-
-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.)
+Agora o código do seu Efeito não usa *nenhum* valor reativo, então suas dependências podem ser vazias (`[]`).
+Pensando da perspectiva do componente, o array de dependências vazio `[]` significa que este Efeito conecta-se à sala de chat apenas quando o componente monta e desconecta apenas quando o componente desmonta. (Lembre-se de que o React ainda [re-sincronizaria uma vez a mais](#how-react-verifies-that-your-effect-can-re-synchronize) no desenvolvimento para estressar sua lógica.)
@@ -510,7 +509,7 @@ function ChatRoom() {
connection.connect();
return () => connection.disconnect();
}, []);
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à sala {roomId}!
;
}
export default function App() {
@@ -518,7 +517,7 @@ export default function App() {
return (
<>
{show && }
{show && }
@@ -529,13 +528,13 @@ export default function App() {
```js src/chat.js
export function createConnection(serverUrl, roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ Connecting to "' + roomId + '" room at ' + serverUrl + '...');
+ console.log('✅ Conectando à sala "' + roomId + '" em ' + serverUrl + '...');
},
disconnect() {
- console.log('❌ Disconnected from "' + roomId + '" room at ' + serverUrl);
+ console.log('❌ Desconectado da sala "' + roomId + '" em ' + serverUrl);
}
};
}
@@ -548,52 +547,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.
+No entanto, se você [pensar da perspectiva do Efeito,](#thinking-from-the-effects-perspective) você não precisa pensar sobre montagem e desmontagem de forma alguma. O que é importante é que você especificou o que seu Efeito faz para iniciar e parar a sincronização. Hoje, ele não tem dependências reativas. Mas se você quiser que o usuário altere `roomId` ou `serverUrl` ao longo do tempo (e eles se tornem reativos), o código do seu Efeito não mudará. Você só precisará adicioná-los às dependências.
-### All variables declared in the component body are reactive {/*all-variables-declared-in-the-component-body-are-reactive*/}
+### Todas as variáveis declaradas no corpo do componente são reativas {/*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.
+Props e estados não são os únicos valores reativos. Valores que você calcula a partir deles também são reativos. Se as props ou estado mudarem, seu componente irá re-renderizar, e os valores calculados a partir deles também mudarão. É por isso que todas as variáveis do corpo do componente usadas pelo Efeito devem estar na lista de dependências do Efeito.
-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:
+Vamos supor que o usuário possa escolher um servidor de chat no dropdown, mas também possa configurar um servidor padrão nas configurações. Suponha que você já colocou o estado de configurações em um [contexto](/learn/scaling-up-with-reducer-and-context) para que você possa ler as `settings` a partir desse contexto. Agora você calcula a `serverUrl` com base no servidor selecionado a partir das props e do servidor padrão:
```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 é reativa
+ const settings = useContext(SettingsContext); // settings é reativa
+ const serverUrl = selectedServerUrl ?? settings.defaultServerUrl; // serverUrl é reativa
useEffect(() => {
- const connection = createConnection(serverUrl, roomId); // Your Effect reads roomId and serverUrl
+ const connection = createConnection(serverUrl, roomId); // Seu Efeito lê roomId e serverUrl
connection.connect();
return () => {
connection.disconnect();
};
- }, [roomId, serverUrl]); // So it needs to re-synchronize when either of them changes!
+ }, [roomId, serverUrl]); // Portanto ele precisa re-sincronizar quando qualquer um deles mudar!
// ...
}
```
-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.
+Neste exemplo, `serverUrl` não é uma prop ou uma variável de estado. É uma variável regular que você calcula durante a renderização. Mas ela é calculada durante a renderização, então pode mudar devido a uma nova renderização. É por isso que ela é reativa.
-**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 os valores dentro do componente (incluindo props, estado e variáveis no corpo do seu componente) são reativos. Qualquer valor reativo pode mudar em uma re-renderização, então você precisa incluir valores reativos como dependências do Efeito.**
-In other words, Effects "react" to all values from the component body.
+Em outras palavras, os Efeitos "reagem" a todos os valores do corpo do componente.
-#### Can global or mutable values be dependencies? {/*can-global-or-mutable-values-be-dependencies*/}
+#### Valores globais ou mutáveis podem ser dependências? {/*can-global-or-mutable-values-be-dependencies*/}
-Mutable values (including global variables) aren't reactive.
+Valores mutáveis (incluindo variáveis globais) não são reativos.
-**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)
+**Um valor mutável como [`location.pathname`](https://developer.mozilla.org/en-US/docs/Web/API/Location/pathname) não pode ser uma dependência.** Ele é mutável, então pode mudar a qualquer momento, completamente fora do fluxo de dados de renderização do React. Alterá-lo não acionaria uma re-renderização do seu componente. Portanto, mesmo que você o especificasse nas dependências, o React *não saberia* para re-sincronizar o Efeito quando ele mudar. Isso também quebra as regras do React porque ler dados mutáveis durante a renderização (que é quando você calcula as dependências) quebra [a pureza da renderização.](/learn/keeping-components-pure) Em vez disso, você deve ler e se inscrever em um valor externo mutável com [`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.
+**Um valor mutável como [`ref.current`](/reference/react/useRef#reference) ou coisas que você lê dele também não podem ser uma dependência.** O objeto ref retornado por `useRef` pode ser uma dependência, mas sua propriedade `current` é intencionalmente mutável. Isso permite que você [monitore algo sem acionar uma re-renderização.](/learn/referencing-values-with-refs) Mas como mudar isso não aciona uma re-renderização, não é um valor reativo e o React não saberá para re-executar seu Efeito quando isso mudar.
-As you'll learn below on this page, a linter will check for these issues automatically.
+Como você aprenderá abaixo nesta página, um linter verificará automaticamente essas questões.
-### React verifies that you specified every reactive value as a dependency {/*react-verifies-that-you-specified-every-reactive-value-as-a-dependency*/}
+### O React verifica que você especificou cada valor reativo como uma dependência {/*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:
+Se seu linter estiver [configurado para o React,](/learn/editor-setup#linting) ele verificará se cada valor reativo usado pelo código do seu Efeito está declarado como sua dependência. Por exemplo, este é um erro de lint porque tanto `roomId` quanto `serverUrl` são reativos:
@@ -601,25 +600,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 é reativa
+ const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl é reativa
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => connection.disconnect();
- }, []); // <-- Something's wrong here!
+ }, []); // <-- Algo está errado aqui!
return (
<>
-
Welcome to the {roomId} room!
+
Bem-vindo à sala {roomId}!
>
);
}
@@ -629,7 +628,7 @@ export default function App() {
return (
<>
-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.
+Isso pode parecer um erro do React, mas na verdade o React está apontando um bug no seu código. Tanto `roomId` quanto `serverUrl` podem mudar ao longo do tempo, mas você está esquecendo de re-sincronizar seu Efeito quando eles mudam. Você permanecerá conectado ao `roomId` e `serverUrl` iniciais mesmo depois que o usuário escolher valores diferentes na UI.
-To fix the bug, follow the linter's suggestion to specify `roomId` and `serverUrl` as dependencies of your Effect:
+Para corrigir o bug, siga a sugestão do linter para especificar `roomId` e `serverUrl` como dependências do seu Efeito:
```js {9}
-function ChatRoom({ roomId }) { // roomId is reactive
- const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl is reactive
+function ChatRoom({ roomId }) { // roomId é reativa
+ const [serverUrl, setServerUrl] = useState('https://localhost:1234'); // serverUrl é reativa
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
- }, [serverUrl, roomId]); // ✅ All dependencies declared
+ }, [serverUrl, roomId]); // ✅ Todas as dependências declaradas
// ...
}
```
-Try this fix in the sandbox above. Verify that the linter error is gone, and the chat re-connects when needed.
+Tente essa correção no sandbox acima. Verifique se o erro do linter desapareceu e que o chat reconecta quando necessário.
-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.
+Em alguns casos, o React *sabe* que um valor nunca muda, mesmo que esteja declarado dentro do componente. Por exemplo, a função [`set`](https://pt.wikipedia.org/wiki/React_(biblioteca)) retornada por `useState` e o objeto ref retornado por [`useRef`](https://pt.wikipedia.org/wiki/React_(biblioteca)) são *estáveis*--são garantidos para não mudar em uma re-renderização. Valores estáveis não são reativos, então você pode omití-los da lista. Incluir eles é permitido: eles não mudarão, então não importa.
-### What to do when you don't want to re-synchronize {/*what-to-do-when-you-dont-want-to-re-synchronize*/}
+### O que fazer quando você não quer re-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.
+No exemplo anterior, você corrigiu o erro do lint listando `roomId` e `serverUrl` como dependências.
-**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:
+**No entanto, você poderia "provar" ao linter que esses valores não são valores reativos,** ou seja, que eles *não podem* mudar como resultado de uma re-renderização. Por exemplo, se `serverUrl` e `roomId` não dependem da renderização e sempre têm os mesmos valores, você pode movê-los para fora do componente. Agora eles não precisam ser dependências:
```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 não é reativa
+const roomId = 'general'; // roomId não é reativa
function ChatRoom() {
useEffect(() => {
- const connection = createConnection(serverUrl, roomId);
+ const connection = createConnection(serverUrl, roomId); // serverUrl e roomId não são reativos
connection.connect();
return () => {
connection.disconnect();
};
- }, []); // ✅ All dependencies declared
+ }, []); // ✅ Todas as dependências declaradas
// ...
}
```
-You can also move them *inside the Effect.* They aren't calculated during rendering, so they're not reactive:
+Você também pode movê-los *para dentro do Efeito.* Eles não estão calculados durante a renderização, então não são reativos:
```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 não é reativa
+ const roomId = 'general'; // roomId não é reativa
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
- }, []); // ✅ All dependencies declared
+ }, []); // ✅ Todas as dependências declaradas
// ...
}
```
-**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.
+**Os Efeitos são blocos de código reativos.** Eles re-sincronizam quando os valores que você lê dentro deles mudam. Diferente dos manipuladores de eventos, que apenas executam uma vez por interação, os Efeitos são executados sempre que a sincronização é necessária.
-**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:
+**Você não pode "escolher" suas dependências.** Suas dependências devem incluir todo [valor reativo](#all-variables-declared-in-the-component-body-are-reactive) que você lê no Efeito. O linter impõe isso. Às vezes isso pode levar a problemas como loops infinitos e à re-sincronização do seu Efeito com frequência demais. Não conserte esses problemas suprimindo o linter! Aqui está o que você pode tentar em vez disso:
-* **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)
+* **Verifique se seu Efeito representa um processo de sincronização independente.** Se seu Efeito não sincroniza nada, [pode ser desnecessário.](/learn/you-might-not-need-an-effect) Se ele sincroniza várias coisas independentes, [divida-o.](/learn/each-effect-represents-a-separate-synchronization-process)
-* **If you want to read the latest value of props or state without "reacting" to it and re-synchronizing the Effect,** you can split your Effect into a reactive part (which you'll keep in the Effect) and a non-reactive part (which you'll extract into something called an _Effect Event_). [Read about separating Events from Effects.](/learn/separating-events-from-effects)
+* **Se você quiser ler o valor mais recente de props ou estado sem "reagir" a ele e re-sincronizar o Efeito,** pode dividir seu Efeito em uma parte reativa (que você manterá no Efeito) e uma parte não reativa (que você extrairá para algo chamado um _Evento de Efeito_). [Saiba mais sobre separar Eventos de Efeitos.](/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)
+* **Evite depender de objetos e funções como dependências.** Se você criar objetos e funções durante a renderização e depois lê-los de um Efeito, eles serão diferentes a cada renderização. Isso fará com que seu Efeito re-sincronize cada vez. [Saiba mais sobre remover dependências desnecessárias de Efeitos.](/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.
+O linter é seu amigo, mas seus poderes são limitados. O linter só sabe quando as dependências estão *erradas*. Ele não sabe *a melhor* maneira de resolver cada caso. Se o linter sugerir uma dependência, mas adicioná-la causar um loop, isso não significa que o linter deve ser ignorado. Você precisa mudar o código dentro (ou fora) do Efeito para que esse valor não seja reativo e não *precise* ser uma dependência.
-If you have an existing codebase, you might have some Effects that suppress the linter like this:
+Se você tiver uma base de código existente, pode ter alguns Efeitos que suprimem o linter assim:
```js {3-4}
useEffect(() => {
// ...
- // 🔴 Avoid suppressing the linter like this:
+ // 🔴 Evite suprimir o linter assim:
// 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!
+Nas [próximas](/learn/separating-events-from-effects) [páginas](/learn/removing-effect-dependencies), você aprenderá a consertar esse código sem quebrar as regras. Sempre vale a pena consertar!
-- 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.
+- Componentes podem montar, atualizar e desmontar.
+- Cada Efeito tem um ciclo de vida separado do componente ao redor.
+- Cada Efeito descreve um processo de sincronização separado que pode *começar* e *parar*.
+- Quando você escreve e lê Efeitos, pense da perspectiva de cada Efeito individual (como iniciar e parar a sincronização) em vez da perspectiva do componente (como ele monta, atualiza ou desmonta).
+- Valores declarados dentro do corpo do componente são "reativos".
+- Valores reativos devem re-sincronizar o Efeito porque podem mudar ao longo do tempo.
+- O linter verifica que todos os valores reativos usados dentro do Efeito estão especificados como dependências.
+- Todos os erros sinalizados pelo linter são legítimos. Sempre há uma maneira de corrigir o código para não quebrar as regras.
-#### Fix reconnecting on every keystroke {/*fix-reconnecting-on-every-keystroke*/}
+#### Corrija a reconexão em cada digitação {/*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.
+Neste exemplo, o componente `ChatRoom` conecta-se à sala de chat quando o componente monta, desconecta quando desmonta e reconecta quando você seleciona uma sala diferente. Esse comportamento está correto, então você precisa mantê-lo 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.
+No entanto, há um problema. Sempre que você digita na caixa de mensagem na parte inferior, o `ChatRoom` *também* reconecta ao chat. (Você pode notar isso limpando o console e digitando na entrada.) Corrija o problema para que isso não aconteça.
-You might need to add a dependency array for this Effect. What dependencies should be there?
+Você pode precisar adicionar um array de dependências para este Efeito. Quais dependências devem estar lá?
@@ -806,7 +805,7 @@ function ChatRoom({ roomId }) {
return (
<>
-
-One solution is to wrap the `setPosition` call into an `if (canMove) { ... }` condition:
+Uma solução é envolver a chamada `setPosition` em uma condição `if (canMove) { ... }`:
@@ -1029,7 +1028,7 @@ export default function App() {
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
- The dot is allowed to move
+ O ponto pode se mover
-Alternatively, you could wrap the *event subscription* logic into an `if (canMove) { ... }` condition:
+Alternativamente, você poderia envolver a lógica *da inscrição do evento* em uma condição `if (canMove) { ... }`:
@@ -1085,7 +1084,7 @@ export default function App() {
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
- The dot is allowed to move
+ O ponto pode se mover
-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.
+Em ambos os casos, `canMove` é uma variável reativa que você lê dentro do Efeito. É por isso que ela deve estar especificada na lista de dependências. Isso garante que o Efeito re-sincronize após cada alteração em seu valor.
-#### Investigate a stale value bug {/*investigate-a-stale-value-bug*/}
+#### Investigue um bug de valor obsoleto {/*investigate-a-stale-value-bug*/}
-In this example, the pink dot should move when the checkbox is on, and should stop moving when the checkbox is off. The logic for this has already been implemented: the `handleMove` event handler checks the `canMove` state variable.
+Neste exemplo, o ponto rosa deve se mover quando a caixa de seleção estiver ligada e deve parar de se mover quando a caixa de seleção estiver desligada. A lógica para isso já foi implementada: o manipulador de eventos `handleMove` verifica a variável 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.
+No entanto, por algum motivo, a variável de estado `canMove` dentro de `handleMove` parece estar "obsoleta": ela está sempre `true`, mesmo depois que você desmarca a caixa de seleção. Como isso é possível? Encontre o erro no código e corrigir.
-If you see a linter rule being suppressed, remove the suppression! That's where the mistakes usually are.
+Se você vê uma regra de lint sendo suprimida, remova a supressão! É aí que geralmente estão os erros.
@@ -1157,7 +1156,7 @@ export default function App() {
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
- The dot is allowed to move
+ O ponto pode se mover
-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!
+O problema com o código original era suprimir a dependência do linter. Se você remover a supressão, verá que este Efeito depende da função `handleMove`. Isso faz sentido: `handleMove` é declarada dentro do corpo do componente, o que a torna um valor reativo. Cada valor reativo deve ser especificado como uma dependência, ou ele pode ficar obsoleto ao longo do tempo!
-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.
+O autor do código original "mentiu" para o React ao dizer que o Efeito não depende (`[]`) de nenhum valor reativo. É por isso que o React não re-sincronizou o Efeito após `canMove` ter mudado (e `handleMove` com ele). Como o React não re-sincronizou o Efeito, o `handleMove` anexado como um listener é a função `handleMove` criada durante a renderização inicial. Durante a renderização inicial, `canMove` era `true`, razão pela qual `handleMove` da renderização inicial sempre verá esse 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.
+**Se você nunca suprimir o linter, você nunca verá problemas com valores obsoletos.** Existem algumas maneiras diferentes de resolver esse bug, mas você sempre deve começar removendo a supressão do linter. Em seguida, altere o código para corrigir o erro de lint.
-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:
+Você pode mudar as dependências do Efeito para `[handleMove]`, mas como será uma função recém-definida a cada renderização, seria mais interessante remover completamente o array de dependências. Então o Efeito *re-sincronizará* após cada re-renderização:
@@ -1222,7 +1221,7 @@ export default function App() {
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
- The dot is allowed to move
+ O ponto pode se mover
-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.
+Essa solução funciona, mas não é ideal. Se você colocar `console.log('Reinscrevendo')` dentro do corpo do Efeito, você notará que agora ele apenas re-inscreve quando você alternar a caixa de seleção (`canMove` muda) ou editar o código. Isso a torna melhor do que a abordagem anterior que sempre se re-inscrevia.
-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`:
+Uma correção melhor seria mover a função `handleMove` *para dentro* do Efeito. Então `handleMove` não será um valor reativo, e assim seu Efeito não dependerá de uma função. Em vez disso, ele precisará depender de `canMove`, que seu código agora lê de dentro do Efeito. Isso corresponde ao comportamento desejado, já que seu Efeito agora permanecerá sincronizado com o valor de `canMove`:
@@ -1281,7 +1280,7 @@ export default function App() {
checked={canMove}
onChange={e => setCanMove(e.target.checked)}
/>
- The dot is allowed to move
+ O ponto pode se mover
-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.
+Tente adicionar `console.log('Reinscrevendo')` dentro do corpo do Efeito e note que agora ele só se re-inscreve quando você alterna a caixa de seleção (`canMove` muda) ou edita o código. Isso a torna uma solução melhor que a anterior.
-You'll learn a more general approach to this type of problem in [Separating Events from Effects.](/learn/separating-events-from-effects)
+Você aprenderá uma abordagem mais geral para esse tipo de problema em [Separando Eventos de Efeitos.](/learn/separating-events-from-effects)
-#### Fix a connection switch {/*fix-a-connection-switch*/}
+#### Corrija uma troca de conexão {/*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.
+Neste exemplo, o serviço de chat em `chat.js` expõe duas APIs diferentes: `createEncryptedConnection` e `createUnencryptedConnection`. O componente `App` principal permite que o usuário escolha entre usar criptografia ou não e, em seguida, passa o método da API correspondente para o componente filho `ChatRoom` como a 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.
+Perceba que, inicialmente, os logs do console dizem que a conexão não está criptografada. Tente alternar a caixa de seleção: nada acontecerá. No entanto, se você mudar a sala selecionada depois disso, o chat irá reconectar *e* habilitar a criptografia (como você verá nas mensagens do console). Este é um bug. Corrija o bug para que alternar a caixa de seleção *também* faça com que o chat reconecte.
-Suppressing the linter is always suspicious. Could this be a bug?
+Suprimir o linter é sempre suspeito. Isso poderia ser um bug?
@@ -1343,7 +1342,7 @@ export default function App() {
return (
<>
- Choose the chat room:{' '}
+ Escolha a sala de chat:{' '}
Welcome to the {roomId} room!;
+ return
Bem-vindo à sala {roomId}!
;
}
```
```js src/chat.js
export function createEncryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)');
+ console.log('✅ 🔐 Conectando à sala "' + roomId + '"... (criptografado)');
},
disconnect() {
- console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)');
+ console.log('❌ 🔐 Desconectado da sala "' + roomId + '" (criptografado)');
}
};
}
export function createUnencryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ Connecting to "' + roomId + '... (unencrypted)');
+ console.log('✅ Conectando à sala "' + roomId + '"... (não criptografado)');
},
disconnect() {
- console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)');
+ console.log('❌ Desconectado da sala "' + roomId + '" (não criptografado)');
}
};
}
@@ -1423,7 +1422,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:
+Se você remover a supressão do linter, verá um erro de lint. O problema é que `createConnection` é uma prop, então é um valor reativo. Ele pode mudar ao longo do tempo! (E de fato, deveria--quando o usuário marcar a caixa de seleção, o componente pai passa um valor diferente da prop `createConnection`.) É por isso que deve ser uma dependência. Inclua-a na lista para corrigir o bug:
@@ -1441,7 +1440,7 @@ export default function App() {
return (
<>
- Choose the chat room:{' '}
+ Escolha a sala de chat:{' '}
connection.disconnect();
}, [roomId, createConnection]);
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à sala {roomId}!
;
}
```
```js src/chat.js
export function createEncryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)');
+ console.log('✅ 🔐 Conectando à sala "' + roomId + '"... (criptografado)');
},
disconnect() {
- console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)');
+ console.log('❌ 🔐 Desconectado da sala "' + roomId + '" (criptografado)');
}
};
}
export function createUnencryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ Connecting to "' + roomId + '... (unencrypted)');
+ console.log('✅ Conectando à sala "' + roomId + '"... (não criptografado)');
},
disconnect() {
- console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)');
+ console.log('❌ Desconectado da sala "' + roomId + '" (não criptografado)');
}
};
}
@@ -1518,7 +1517,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:
+É correto que `createConnection` seja uma dependência. No entanto, esse código é um pouco frágil porque alguém poderia editar o componente `App` para passar uma função inline como valor dessa prop. Nesse caso, seu valor seria diferente a cada vez que o componente `App` re-renderizasse, então o Efeito poderia re-sincronizar com frequência demais. Para evitar isso, você pode passar `isEncrypted` para baixo em vez disso:
@@ -1532,7 +1531,7 @@ export default function App() {
return (
<>
- Choose the chat room:{' '}
+ Escolha a sala de chat:{' '}
connection.disconnect();
}, [roomId, isEncrypted]);
- return
Welcome to the {roomId} room!
;
+ return
Bem-vindo à sala {roomId}!
;
}
```
```js src/chat.js
export function createEncryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ 🔐 Connecting to "' + roomId + '... (encrypted)');
+ console.log('✅ 🔐 Conectando à sala "' + roomId + '"... (criptografado)');
},
disconnect() {
- console.log('❌ 🔐 Disconnected from "' + roomId + '" room (encrypted)');
+ console.log('❌ 🔐 Desconectado da sala "' + roomId + '" (criptografado)');
}
};
}
export function createUnencryptedConnection(roomId) {
- // A real implementation would actually connect to the server
+ // Uma implementação real conectaria realmente ao servidor
return {
connect() {
- console.log('✅ Connecting to "' + roomId + '... (unencrypted)');
+ console.log('✅ Conectando à sala "' + roomId + '"... (não criptografado)');
},
disconnect() {
- console.log('❌ Disconnected from "' + roomId + '" room (unencrypted)');
+ console.log('❌ Desconectado da sala "' + roomId + '" (não criptografado)');
}
};
}
@@ -1613,21 +1612,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)
+Nesta versão, o componente `App` passa uma prop booleana em vez de uma função. Dentro do Efeito, você decide qual função usar. Como `createEncryptedConnection` e `createUnencryptedConnection` estão declarados fora do componente, eles não são reativos e não precisam ser dependências. Você aprenderá mais sobre isso em [Remover Dependências de Efeito.](/learn/removing-effect-dependencies)
-#### Populate a chain of select boxes {/*populate-a-chain-of-select-boxes*/}
+#### Preencha uma cadeia de caixas de seleção {/*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.
+Neste exemplo, há duas caixas de seleção. Uma caixa de seleção permite que o usuário escolha um planeta. Outra caixa de seleção permite que o usuário escolha um lugar *nesse planeta*. A segunda caixa não funciona ainda. Sua tarefa é fazê-la mostrar os lugares no planeta escolhido.
-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.
+Olhe como a primeira caixa de seleção funciona. Ela popula o estado `planetList` com o resultado da chamada à API `"/planets"`. O ID do planeta atualmente selecionado é mantido na variável de estado `planetId`. Você precisa encontrar onde adicionar um código adicional para que a variável de estado `placeList` seja preenchida com o resultado da chamada à 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.
+Se você implementar isso corretamente, selecionar um planeta deve popular a lista de lugares. Mudar um planeta deve mudar a lista de lugares.
-If you have two independent synchronization processes, you need to write two separate Effects.
+Se você tiver dois processos de sincronização independentes, precisará escrever dois Efeitos separados.
@@ -1648,9 +1647,9 @@ export default function Page() {
let ignore = false;
fetchData('/planets').then(result => {
if (!ignore) {
- console.log('Fetched a list of planets.');
+ console.log('Lista de planetas buscada.');
setPlanetList(result);
- setPlanetId(result[0].id); // Select the first planet
+ setPlanetId(result[0].id); // Seleciona o primeiro planeta
}
});
return () => {
@@ -1661,7 +1660,7 @@ export default function Page() {
return (
<>
- Pick a planet:{' '}
+ Escolha um planeta:{' '}
- Pick a place:{' '}
+ Escolha um lugar:{' '}
-
You are going to: {placeId || '???'} on {planetId || '???'}
+
Você está indo para: {placeId || '???'} em {planetId || '???'}
>
);
}
@@ -1694,10 +1693,10 @@ export function fetchData(url) {
} else if (url.startsWith('/planets/')) {
const match = url.match(/^\/planets\/([\w-]+)\/places(\/)?$/);
if (!match || !match[1] || !match[1].length) {
- throw Error('Expected URL like "/planets/earth/places". Received: "' + url + '".');
+ throw Error('Esperava uma URL como "/planets/earth/places". Recebido: "' + url + '".');
}
return fetchPlaces(match[1]);
- } else throw Error('Expected URL like "/planets" or "/planets/earth/places". Received: "' + url + '".');
+ } else throw Error('Esperava uma URL como "/planets" ou "/planets/earth/places". Recebido: "' + url + '".');
}
async function fetchPlanets() {
@@ -1705,13 +1704,13 @@ async function fetchPlanets() {
setTimeout(() => {
resolve([{
id: 'earth',
- name: 'Earth'
+ name: 'Terra'
}, {
id: 'venus',
- name: 'Venus'
+ name: 'Vênus'
}, {
id: 'mars',
- name: 'Mars'
+ name: 'Marte'
}]);
}, 1000);
});
@@ -1720,8 +1719,8 @@ async function fetchPlanets() {
async function fetchPlaces(planetId) {
if (typeof planetId !== 'string') {
throw Error(
- 'fetchPlaces(planetId) expects a string argument. ' +
- 'Instead received: ' + planetId + '.'
+ 'fetchPlaces(planetId) espera um argumento do tipo string. ' +
+ 'Recebido: ' + planetId + '.'
);
}
return new Promise(resolve => {
@@ -1732,10 +1731,10 @@ async function fetchPlaces(planetId) {
name: 'Laos'
}, {
id: 'spain',
- name: 'Spain'
+ name: 'Espanha'
}, {
id: 'vietnam',
- name: 'Vietnam'
+ name: 'Vietnã'
}]);
} else if (planetId === 'venus') {
resolve([{
@@ -1751,15 +1750,15 @@ async function fetchPlaces(planetId) {
} else if (planetId === 'mars') {
resolve([{
id: 'aluminum-city',
- name: 'Aluminum City'
+ name: 'Cidade de Alumínio'
}, {
id: 'new-new-york',
- name: 'New New York'
+ name: 'Nova Nova Iorque'
}, {
id: 'vishniac',
name: 'Vishniac'
}]);
- } else throw Error('Unknown planet ID: ' + planetId);
+ } else throw Error('ID de planeta desconhecido: ' + planetId);
}, 1000);
});
}
@@ -1773,12 +1772,12 @@ label { display: block; margin-bottom: 10px; }
-There are two independent synchronization processes:
+Existem dois processos de sincronização independentes:
-- 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`.
+- A primeira caixa de seleção está sincronizada com a lista remota de planetas.
+- A segunda caixa de seleção está sincronizada com a lista remota de lugares para o atual `planetId`.
-This is why it makes sense to describe them as two separate Effects. Here's an example of how you could do this:
+É por isso que faz sentido descrevê-los como dois Efeitos separados. Aqui está um exemplo de como você poderia fazer isso:
@@ -1797,313 +1796,10 @@ export default function Page() {
let ignore = false;
fetchData('/planets').then(result => {
if (!ignore) {
- console.log('Fetched a list of planets.');
+ console.log('Lista de planetas buscada.');
setPlanetList(result);
- setPlanetId(result[0].id); // Select the first planet
+ setPlanetId(result[0].id); // Seleciona o primeiro planeta
}
});
return () => {
- ignore = true;
- }
- }, []);
-
- useEffect(() => {
- if (planetId === '') {
- // Nothing is selected in the first box yet
- return;
- }
-
- let ignore = false;
- fetchData('/planets/' + planetId + '/places').then(result => {
- if (!ignore) {
- console.log('Fetched a list of places on "' + planetId + '".');
- setPlaceList(result);
- setPlaceId(result[0].id); // Select the first place
- }
- });
- return () => {
- ignore = true;
- }
- }, [planetId]);
-
- return (
- <>
-
- Pick a planet:{' '}
-
-
-
- Pick a place:{' '}
-
-
-
-
You are going to: {placeId || '???'} on {planetId || '???'}
- >
- );
-}
-```
-
-```js src/api.js hidden
-export function fetchData(url) {
- if (url === '/planets') {
- return fetchPlanets();
- } else if (url.startsWith('/planets/')) {
- const match = url.match(/^\/planets\/([\w-]+)\/places(\/)?$/);
- if (!match || !match[1] || !match[1].length) {
- throw Error('Expected URL like "/planets/earth/places". Received: "' + url + '".');
- }
- return fetchPlaces(match[1]);
- } else throw Error('Expected URL like "/planets" or "/planets/earth/places". Received: "' + url + '".');
-}
-
-async function fetchPlanets() {
- return new Promise(resolve => {
- setTimeout(() => {
- resolve([{
- id: 'earth',
- name: 'Earth'
- }, {
- id: 'venus',
- name: 'Venus'
- }, {
- id: 'mars',
- name: 'Mars'
- }]);
- }, 1000);
- });
-}
-
-async function fetchPlaces(planetId) {
- if (typeof planetId !== 'string') {
- throw Error(
- 'fetchPlaces(planetId) expects a string argument. ' +
- 'Instead received: ' + planetId + '.'
- );
- }
- return new Promise(resolve => {
- setTimeout(() => {
- if (planetId === 'earth') {
- resolve([{
- id: 'laos',
- name: 'Laos'
- }, {
- id: 'spain',
- name: 'Spain'
- }, {
- id: 'vietnam',
- name: 'Vietnam'
- }]);
- } else if (planetId === 'venus') {
- resolve([{
- id: 'aurelia',
- name: 'Aurelia'
- }, {
- id: 'diana-chasma',
- name: 'Diana Chasma'
- }, {
- id: 'kumsong-vallis',
- name: 'Kŭmsŏng Vallis'
- }]);
- } else if (planetId === 'mars') {
- resolve([{
- id: 'aluminum-city',
- name: 'Aluminum City'
- }, {
- id: 'new-new-york',
- name: 'New New York'
- }, {
- id: 'vishniac',
- name: 'Vishniac'
- }]);
- } else throw Error('Unknown planet ID: ' + planetId);
- }, 1000);
- });
-}
-```
-
-```css
-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.
-
-Instead, to reduce repetition, you can extract some logic into a custom Hook like `useSelectOptions` below:
-
-
-
-```js src/App.js
-import { useState } from 'react';
-import { useSelectOptions } from './useSelectOptions.js';
-
-export default function Page() {
- const [
- planetList,
- planetId,
- setPlanetId
- ] = useSelectOptions('/planets');
-
- const [
- placeList,
- placeId,
- setPlaceId
- ] = useSelectOptions(planetId ? `/planets/${planetId}/places` : null);
-
- return (
- <>
-
- Pick a planet:{' '}
-
-
-
- Pick a place:{' '}
-
-
-
-
You are going to: {placeId || '...'} on {planetId || '...'}
- >
- );
-}
-```
-
-```js src/useSelectOptions.js
-import { useState, useEffect } from 'react';
-import { fetchData } from './api.js';
-
-export function useSelectOptions(url) {
- const [list, setList] = useState(null);
- const [selectedId, setSelectedId] = useState('');
- useEffect(() => {
- if (url === null) {
- return;
- }
-
- let ignore = false;
- fetchData(url).then(result => {
- if (!ignore) {
- setList(result);
- setSelectedId(result[0].id);
- }
- });
- return () => {
- ignore = true;
- }
- }, [url]);
- return [list, selectedId, setSelectedId];
-}
-```
-
-```js src/api.js hidden
-export function fetchData(url) {
- if (url === '/planets') {
- return fetchPlanets();
- } else if (url.startsWith('/planets/')) {
- const match = url.match(/^\/planets\/([\w-]+)\/places(\/)?$/);
- if (!match || !match[1] || !match[1].length) {
- throw Error('Expected URL like "/planets/earth/places". Received: "' + url + '".');
- }
- return fetchPlaces(match[1]);
- } else throw Error('Expected URL like "/planets" or "/planets/earth/places". Received: "' + url + '".');
-}
-
-async function fetchPlanets() {
- return new Promise(resolve => {
- setTimeout(() => {
- resolve([{
- id: 'earth',
- name: 'Earth'
- }, {
- id: 'venus',
- name: 'Venus'
- }, {
- id: 'mars',
- name: 'Mars'
- }]);
- }, 1000);
- });
-}
-
-async function fetchPlaces(planetId) {
- if (typeof planetId !== 'string') {
- throw Error(
- 'fetchPlaces(planetId) expects a string argument. ' +
- 'Instead received: ' + planetId + '.'
- );
- }
- return new Promise(resolve => {
- setTimeout(() => {
- if (planetId === 'earth') {
- resolve([{
- id: 'laos',
- name: 'Laos'
- }, {
- id: 'spain',
- name: 'Spain'
- }, {
- id: 'vietnam',
- name: 'Vietnam'
- }]);
- } else if (planetId === 'venus') {
- resolve([{
- id: 'aurelia',
- name: 'Aurelia'
- }, {
- id: 'diana-chasma',
- name: 'Diana Chasma'
- }, {
- id: 'kumsong-vallis',
- name: 'Kŭmsŏng Vallis'
- }]);
- } else if (planetId === 'mars') {
- resolve([{
- id: 'aluminum-city',
- name: 'Aluminum City'
- }, {
- id: 'new-new-york',
- name: 'New New York'
- }, {
- id: 'vishniac',
- name: 'Vishniac'
- }]);
- } else throw Error('Unknown planet ID: ' + planetId);
- }, 1000);
- });
-}
-```
-
-```css
-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.
-
-
-
-
+
\ No newline at end of file