diff --git a/src/content/learn/extracting-state-logic-into-a-reducer.md b/src/content/learn/extracting-state-logic-into-a-reducer.md
index 5c08c0123..e7448096b 100644
--- a/src/content/learn/extracting-state-logic-into-a-reducer.md
+++ b/src/content/learn/extracting-state-logic-into-a-reducer.md
@@ -1,25 +1,25 @@
---
-title: Extracting State Logic into a Reducer
+title: Extraindo a Lógica de Estado em um Reducer
---
-Components with many state updates spread across many event handlers can get overwhelming. For these cases, you can consolidate all the state update logic outside your component in a single function, called a _reducer._
+Componentes com muitas atualizações de estado distribuídas em vários manipuladores de eventos podem se tornar complexos. Para esses casos, você pode consolidar toda a lógica de atualização de estado fora do seu componente em uma única função, chamada de _reducer._
-- What a reducer function is
-- How to refactor `useState` to `useReducer`
-- When to use a reducer
-- How to write one well
+- O que é uma função de reducer
+- Como refatorar `useState` para `useReducer`
+- Quando usar um reducer
+- Como escrever um bom reducer
-## Consolidate state logic with a reducer {/*consolidate-state-logic-with-a-reducer*/}
+## Consolidar a lógica de estado com um reducer {/*consolidate-state-logic-with-a-reducer*/}
-As your components grow in complexity, it can get harder to see at a glance all the different ways in which a component's state gets updated. For example, the `TaskApp` component below holds an array of `tasks` in state and uses three different event handlers to add, remove, and edit tasks:
+À medida que seus componentes crescem em complexidade, pode ser difícil ver rapidamente todas as diferentes maneiras pelas quais o estado de um componente é atualizado. Por exemplo, o componente `TaskApp` abaixo contém uma array de `tasks` no estado e usa três manipuladores de eventos diferentes para adicionar, remover e editar tarefas:
@@ -179,17 +179,17 @@ li {
-Each of its event handlers calls `setTasks` in order to update the state. As this component grows, so does the amount of state logic sprinkled throughout it. To reduce this complexity and keep all your logic in one easy-to-access place, you can move that state logic into a single function outside your component, **called a "reducer".**
+Cada um de seus manipuladores de eventos chama `setTasks` para atualizar o estado. À medida que esse componente cresce, a quantidade de lógica de estado espalhada por ele também aumenta. Para reduzir essa complexidade e manter toda a sua lógica em um só lugar de fácil acesso, você pode mover essa lógica de estado para uma única função fora do seu componente, **chamada de "reducer".**
-Reducers are a different way to handle state. You can migrate from `useState` to `useReducer` in three steps:
+Reducers são uma maneira diferente de lidar com o estado. Você pode migrar de `useState` para `useReducer` em três etapas:
-1. **Move** from setting state to dispatching actions.
-2. **Write** a reducer function.
-3. **Use** the reducer from your component.
+1. **Mover** de definir o estado para disparar ações.
+2. **Escrever** uma função de reducer.
+3. **Usar** o reducer do seu componente.
-### Step 1: Move from setting state to dispatching actions {/*step-1-move-from-setting-state-to-dispatching-actions*/}
+### Etapa 1: Mover de definir o estado para disparar ações {/*step-1-move-from-setting-state-to-dispatching-actions*/}
-Your event handlers currently specify _what to do_ by setting state:
+Seus manipuladores de eventos atualmente especificam _o que fazer_ definindo o estado:
```js
function handleAddTask(text) {
@@ -220,13 +220,13 @@ function handleDeleteTask(taskId) {
}
```
-Remove all the state setting logic. What you are left with are three event handlers:
+Remova toda a lógica de definição de estado. O que resta são três manipuladores de eventos:
-- `handleAddTask(text)` is called when the user presses "Add".
-- `handleChangeTask(task)` is called when the user toggles a task or presses "Save".
-- `handleDeleteTask(taskId)` is called when the user presses "Delete".
+- `handleAddTask(text)` é chamado quando o usuário pressiona "Add".
+- `handleChangeTask(task)` é chamado quando o usuário alterna uma tarefa ou pressiona "Save".
+- `handleDeleteTask(taskId)` é chamado quando o usuário pressiona "Delete".
-Managing state with reducers is slightly different from directly setting state. Instead of telling React "what to do" by setting state, you specify "what the user just did" by dispatching "actions" from your event handlers. (The state update logic will live elsewhere!) So instead of "setting `tasks`" via an event handler, you're dispatching an "added/changed/deleted a task" action. This is more descriptive of the user's intent.
+Gerenciar o estado com reducers é um pouco diferente de definir o estado diretamente. Em vez de dizer ao React "o que fazer" definindo o estado, você especifica "o que o usuário acabou de fazer" disparando "ações" de seus manipuladores de eventos. (A lógica de atualização de estado viverá em outro lugar!) Então, em vez de "definir `tasks`" por meio de um manipulador de eventos, você está despachando uma ação de "adicionado/alterado/excluído uma tarefa". Isso é mais descritivo da intenção do usuário.
```js
function handleAddTask(text) {
@@ -252,7 +252,7 @@ function handleDeleteTask(taskId) {
}
```
-The object you pass to `dispatch` is called an "action":
+O objeto que você passa para `dispatch` é chamado de "action":
```js {3-7}
function handleDeleteTask(taskId) {
@@ -266,27 +266,27 @@ function handleDeleteTask(taskId) {
}
```
-It is a regular JavaScript object. You decide what to put in it, but generally it should contain the minimal information about _what happened_. (You will add the `dispatch` function itself in a later step.)
+É um objeto JavaScript comum. Você decide o que colocar nele, mas geralmente ele deve conter o mínimo de informações sobre _o que aconteceu_. (Você adicionará a própria função `dispatch` em uma etapa posterior.)
-An action object can have any shape.
+Um objeto de action pode ter qualquer formato.
-By convention, it is common to give it a string `type` that describes what happened, and pass any additional information in other fields. The `type` is specific to a component, so in this example either `'added'` or `'added_task'` would be fine. Choose a name that says what happened!
+Por convenção, é comum dar a ele um `type` de string que descreve o que aconteceu e passar informações adicionais em outros campos. O `type` é específico de um componente, então neste exemplo, tanto `'added'` como `'added_task'` seriam bons. Escolha um nome que diga o que aconteceu!
```js
dispatch({
- // specific to component
+ // específico do componente
type: 'what_happened',
- // other fields go here
+ // outros campos vão aqui
});
```
-### Step 2: Write a reducer function {/*step-2-write-a-reducer-function*/}
+### Etapa 2: Escrever uma função de reducer {/*step-2-write-a-reducer-function*/}
-A reducer function is where you will put your state logic. It takes two arguments, the current state and the action object, and it returns the next state:
+Uma função de reducer é onde você colocará sua lógica de estado. Ela recebe dois argumentos, o estado atual e o objeto action, e retorna o próximo estado:
```js
function yourReducer(state, action) {
@@ -294,15 +294,15 @@ function yourReducer(state, action) {
}
```
-React will set the state to what you return from the reducer.
+React definirá o estado para o que você retornar do reducer.
-To move your state setting logic from your event handlers to a reducer function in this example, you will:
+Para mover sua lógica de definição de estado de seus manipuladores de eventos para uma função de reducer neste exemplo, você fará o seguinte:
-1. Declare the current state (`tasks`) as the first argument.
-2. Declare the `action` object as the second argument.
-3. Return the _next_ state from the reducer (which React will set the state to).
+1. Declare o estado atual (`tasks`) como o primeiro argumento.
+2. Declare o objeto `action` como o segundo argumento.
+3. Retorne o _próximo_ estado do reducer (que o React definirá o estado).
-Here is all the state setting logic migrated to a reducer function:
+Aqui está toda a lógica de definição de estado migrada para uma função de reducer:
```js
function tasksReducer(tasks, action) {
@@ -331,13 +331,13 @@ function tasksReducer(tasks, action) {
}
```
-Because the reducer function takes state (`tasks`) as an argument, you can **declare it outside of your component.** This decreases the indentation level and can make your code easier to read.
+Como a função de reducer recebe o estado (`tasks`) como um argumento, você pode **declará-la fora do seu componente.** Isso diminui o nível de indentação e pode tornar seu código mais fácil de ler.
-The code above uses if/else statements, but it's a convention to use [switch statements](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/switch) inside reducers. The result is the same, but it can be easier to read switch statements at a glance.
+O código acima usa instruções if/else, mas é uma convenção usar [instruções switch](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/switch) dentro dos reducers. O resultado é o mesmo, mas pode ser mais fácil ler instruções switch rapidamente.
-We'll be using them throughout the rest of this documentation like so:
+Os usaremos ao longo do restante desta documentação assim:
```js
function tasksReducer(tasks, action) {
@@ -371,19 +371,17 @@ function tasksReducer(tasks, action) {
}
```
-We recommend wrapping each `case` block into the `{` and `}` curly braces so that variables declared inside of different `case`s don't clash with each other. Also, a `case` should usually end with a `return`. If you forget to `return`, the code will "fall through" to the next `case`, which can lead to mistakes!
+Recomendamos que você envolva cada bloco `case` nas chaves `{` e `}` para que as variáveis declaradas dentro de diferentes `case`s não entrem em conflito entre si. Além disso, um `case` geralmente deve terminar com um `return`. Se você esquecer de fazer `return`, o código "cairá" para o próximo `case`, o que pode levar a erros!
-If you're not yet comfortable with switch statements, using if/else is completely fine.
+Se você ainda não está confortável com instruções switch, usar if/else é totalmente aceitável.
-
+#### Por que os reducers são chamados assim? {/*why-are-reducers-called-this-way*/}
-#### Why are reducers called this way? {/*why-are-reducers-called-this-way*/}
+Embora os reducers possam "reduzir" a quantidade de código dentro do seu componente, eles são na verdade nomeados em homenagem à operação [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) que você pode realizar em arrays.
-Although reducers can "reduce" the amount of code inside your component, they are actually named after the [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) operation that you can perform on arrays.
-
-The `reduce()` operation lets you take an array and "accumulate" a single value out of many:
+A operação `reduce()` permite que você pegue uma array e "acumule" um único valor a partir de muitos:
```
const arr = [1, 2, 3, 4, 5];
@@ -392,9 +390,9 @@ const sum = arr.reduce(
); // 1 + 2 + 3 + 4 + 5
```
-The function you pass to `reduce` is known as a "reducer". It takes the _result so far_ and the _current item,_ then it returns the _next result._ React reducers are an example of the same idea: they take the _state so far_ and the _action_, and return the _next state._ In this way, they accumulate actions over time into state.
+A função que você passa para `reduce` é conhecida como "reducer". Ele pega o _resultado até agora_ e o _item atual_ e, em seguida, retorna o _próximo resultado._ Os reducers do React são um exemplo da mesma ideia: eles pegam o _estado até agora_ e a _action_ e retornam o _próximo estado._ Dessa forma, eles acumulam ações ao longo do tempo no estado.
-You could even use the `reduce()` method with an `initialState` and an array of `actions` to calculate the final state by passing your reducer function to it:
+Você pode até usar o método `reduce()` com um `initialState` e uma array de `actions` para calcular o estado final passando sua função de reducer para ele:
@@ -453,43 +451,43 @@ export default function tasksReducer(tasks, action) {
-You probably won't need to do this yourself, but this is similar to what React does!
+Você provavelmente não precisará fazer isso sozinho, mas isso é semelhante ao que o React faz!
-### Step 3: Use the reducer from your component {/*step-3-use-the-reducer-from-your-component*/}
+### Etapa 3: Usar o reducer do seu componente {/*step-3-use-the-reducer-from-your-component*/}
-Finally, you need to hook up the `tasksReducer` to your component. Import the `useReducer` Hook from React:
+Finalmente, você precisa conectar o `tasksReducer` ao seu componente. Importe o Hook `useReducer` do React:
```js
import { useReducer } from 'react';
```
-Then you can replace `useState`:
+Então você pode substituir `useState`:
```js
const [tasks, setTasks] = useState(initialTasks);
```
-with `useReducer` like so:
+com `useReducer` assim:
```js
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
```
-The `useReducer` Hook is similar to `useState`—you must pass it an initial state and it returns a stateful value and a way to set state (in this case, the dispatch function). But it's a little different.
+O Hook `useReducer` é semelhante a `useState` – você deve passar um estado inicial e ele retorna um valor com estado e uma maneira de definir o estado (neste caso, a função de dispatch). Mas é um pouco diferente.
-The `useReducer` Hook takes two arguments:
+O Hook `useReducer` recebe dois argumentos:
-1. A reducer function
-2. An initial state
+1. Uma função de reducer
+2. Um estado inicial
-And it returns:
+E ele retorna:
-1. A stateful value
-2. A dispatch function (to "dispatch" user actions to the reducer)
+1. Um valor com estado
+2. Uma função de dispatch (para "despachar" ações do usuário para o reducer)
-Now it's fully wired up! Here, the reducer is declared at the bottom of the component file:
+Agora está totalmente conectado! Aqui, o reducer é declarado na parte inferior do arquivo do componente:
@@ -612,7 +610,9 @@ export default function TaskList({tasks, onChangeTask, onDeleteTask}) {
);
}
+```
+```js
function Task({task, onChange, onDelete}) {
const [isEditing, setIsEditing] = useState(false);
let taskContent;
@@ -674,7 +674,7 @@ li {
-If you want, you can even move the reducer to a different file:
+Se quiser, você pode até mesmo mover o **reducer** para um arquivo diferente:
@@ -862,30 +862,30 @@ li {
-Component logic can be easier to read when you separate concerns like this. Now the event handlers only specify _what happened_ by dispatching actions, and the reducer function determines _how the state updates_ in response to them.
+A lógica do componente pode ser mais fácil de ler quando você separa as preocupações dessa forma. Agora, os *event handlers* (manipuladores de eventos) especificam apenas *o que aconteceu* ao despachar *actions* (ações), e a função *reducer* (redutor) determina *como o estado atualiza* em resposta a elas.
-## Comparing `useState` and `useReducer` {/*comparing-usestate-and-usereducer*/}
+## Comparando `useState` e `useReducer` {/*comparing-usestate-and-usereducer*/}
-Reducers are not without downsides! Here's a few ways you can compare them:
+Os *reducers* (redutores) não são isentos de desvantagens! Aqui estão algumas maneiras de compará-los:
-- **Code size:** Generally, with `useState` you have to write less code upfront. With `useReducer`, you have to write both a reducer function _and_ dispatch actions. However, `useReducer` can help cut down on the code if many event handlers modify state in a similar way.
-- **Readability:** `useState` is very easy to read when the state updates are simple. When they get more complex, they can bloat your component's code and make it difficult to scan. In this case, `useReducer` lets you cleanly separate the _how_ of update logic from the _what happened_ of event handlers.
-- **Debugging:** When you have a bug with `useState`, it can be difficult to tell _where_ the state was set incorrectly, and _why_. With `useReducer`, you can add a console log into your reducer to see every state update, and _why_ it happened (due to which `action`). If each `action` is correct, you'll know that the mistake is in the reducer logic itself. However, you have to step through more code than with `useState`.
-- **Testing:** A reducer is a pure function that doesn't depend on your component. This means that you can export and test it separately in isolation. While generally it's best to test components in a more realistic environment, for complex state update logic it can be useful to assert that your reducer returns a particular state for a particular initial state and action.
-- **Personal preference:** Some people like reducers, others don't. That's okay. It's a matter of preference. You can always convert between `useState` and `useReducer` back and forth: they are equivalent!
+- **Tamanho do código:** Geralmente, com o `useState`, você precisa escrever menos código antecipadamente. Com o `useReducer`, você precisa escrever uma função *reducer* (redutora) _e_ despachar *actions* (ações). No entanto, `useReducer` pode ajudar a reduzir o código se muitos *event handlers* (manipuladores de eventos) modificarem o estado de maneira semelhante.
+- **Legibilidade:** `useState` é muito fácil de ler quando as atualizações de estado são simples. Quando elas se tornam mais complexas, podem inflar o código do seu componente e torná-lo difícil de escanear. Nesse caso, o `useReducer` permite que você separe o *como* da lógica de atualização do *o que aconteceu* nos *event handlers* (manipuladores de eventos).
+- **Depuração:** Quando você tem um *bug* com `useState`, pode ser difícil dizer *onde* o estado foi definido incorretamente e *por quê*. Com `useReducer`, você pode adicionar um `console.log` em seu *reducer* (redutor) para ver cada atualização de estado e *por que* isso aconteceu (devido a qual `action`). Se cada `action` estiver correta, você saberá que o erro está na própria lógica do *reducer* (redutor). No entanto, você tem que percorrer mais código do que com `useState`.
+- **Testes:** Um *reducer* (redutor) é uma função pura que não depende do seu componente. Isso significa que você pode exportá-lo e testá-lo separadamente em isolamento. Embora geralmente seja melhor testar componentes em um ambiente mais realista, para uma lógica complexa de atualização de estado, pode ser útil afirmar que seu *reducer* (redutor) retorna um estado particular para um estado inicial e ação particulares.
+- **Preferência pessoal:** Algumas pessoas gostam de *reducers* (redutores), outras não. Tudo bem. É uma questão de preferência. Você sempre pode converter entre `useState` e `useReducer` para frente e para trás: eles são equivalentes!
-We recommend using a reducer if you often encounter bugs due to incorrect state updates in some component, and want to introduce more structure to its code. You don't have to use reducers for everything: feel free to mix and match! You can even `useState` and `useReducer` in the same component.
+Recomendamos o uso de um *reducer* (redutor) se você frequentemente encontrar *bugs* devido a atualizações de estado incorretas em algum componente e quiser introduzir mais estrutura em seu código. Você não precisa usar *reducers* (redutores) para tudo: sinta-se à vontade para misturar e combinar! Você pode até mesmo usar `useState` e `useReducer` no mesmo componente.
-## Writing reducers well {/*writing-reducers-well*/}
+## Escrevendo reducers bem {/*writing-reducers-well*/}
-Keep these two tips in mind when writing reducers:
+Tenha em mente estas duas dicas ao escrever *reducers* (redutores):
-- **Reducers must be pure.** Similar to [state updater functions](/learn/queueing-a-series-of-state-updates), reducers run during rendering! (Actions are queued until the next render.) This means that reducers [must be pure](/learn/keeping-components-pure)—same inputs always result in the same output. They should not send requests, schedule timeouts, or perform any side effects (operations that impact things outside the component). They should update [objects](/learn/updating-objects-in-state) and [arrays](/learn/updating-arrays-in-state) without mutations.
-- **Each action describes a single user interaction, even if that leads to multiple changes in the data.** For example, if a user presses "Reset" on a form with five fields managed by a reducer, it makes more sense to dispatch one `reset_form` action rather than five separate `set_field` actions. If you log every action in a reducer, that log should be clear enough for you to reconstruct what interactions or responses happened in what order. This helps with debugging!
+- **Os reducers devem ser puros.** Semelhante às [funções de atualizador de estado](/learn/queueing-a-series-of-state-updates), os *reducers* (redutores) são executados durante a renderização! (As ações são enfileiradas até a próxima renderização.) Isso significa que os *reducers* (redutores) [devem ser puros](/learn/keeping-components-pure)—as mesmas entradas sempre resultam na mesma saída. Eles não devem enviar solicitações, agendar *timeouts* (tempos limite) ou realizar quaisquer *side effects* (efeitos colaterais) (operações que afetam coisas fora do componente). Eles devem atualizar [objetos](/learn/updating-objects-in-state) e [arrays](/learn/updating-arrays-in-state) sem mutações.
+- **Cada ação descreve uma única interação do usuário, mesmo que isso leve a várias mudanças nos dados.** Por exemplo, se um usuário pressionar "Redefinir" em um formulário com cinco campos gerenciados por um *reducer* (redutor), faz mais sentido despachar uma única ação `reset_form` em vez de cinco ações `set_field` separadas. Se você registrar cada ação em um *reducer* (redutor), esse registro deve ser claro o suficiente para que você reconstrua quais interações ou respostas aconteceram e em que ordem. Isso ajuda na depuração!
-## Writing concise reducers with Immer {/*writing-concise-reducers-with-immer*/}
+## Escrevendo reducers concisos com Immer {/*writing-concise-reducers-with-immer*/}
-Just like with [updating objects](/learn/updating-objects-in-state#write-concise-update-logic-with-immer) and [arrays](/learn/updating-arrays-in-state#write-concise-update-logic-with-immer) in regular state, you can use the Immer library to make reducers more concise. Here, [`useImmerReducer`](https://github.com/immerjs/use-immer#useimmerreducer) lets you mutate the state with `push` or `arr[i] =` assignment:
+Assim como com [a atualização de objetos](/learn/updating-objects-in-state#write-concise-update-logic-with-immer) e [arrays](/learn/updating-arrays-in-state#write-concise-update-logic-with-immer) no estado normal, você pode usar a biblioteca Immer para tornar os *reducers* (redutores) mais concisos. Aqui, [`useImmerReducer`](https://github.com/immerjs/use-immer#useimmerreducer) permite que você mute o estado com atribuição `push` ou `arr[i] =`:
@@ -1082,34 +1082,34 @@ li {
-Reducers must be pure, so they shouldn't mutate state. But Immer provides you with a special `draft` object which is safe to mutate. Under the hood, Immer will create a copy of your state with the changes you made to the `draft`. This is why reducers managed by `useImmerReducer` can mutate their first argument and don't need to return state.
+Os *reducers* (redutores) devem ser puros, portanto, não devem mutar o estado. Mas o Immer fornece a você um objeto `draft` especial que é seguro para mutar. Por baixo, o Immer criará uma cópia do seu estado com as alterações que você fez no `draft`. É por isso que os *reducers* (redutores) gerenciados por `useImmerReducer` podem mutar seu primeiro argumento e não precisam retornar o estado.
-- To convert from `useState` to `useReducer`:
- 1. Dispatch actions from event handlers.
- 2. Write a reducer function that returns the next state for a given state and action.
- 3. Replace `useState` with `useReducer`.
-- Reducers require you to write a bit more code, but they help with debugging and testing.
-- Reducers must be pure.
-- Each action describes a single user interaction.
-- Use Immer if you want to write reducers in a mutating style.
+- Para converter de `useState` para `useReducer`:
+ 1. Despache *actions* (ações) a partir de *event handlers* (manipuladores de eventos).
+ 2. Escreva uma função *reducer* (redutora) que retorna o próximo estado para um determinado estado e ação.
+ 3. Substitua `useState` por `useReducer`.
+- Os *reducers* (redutores) exigem que você escreva um pouco mais de código, mas eles ajudam na depuração e nos testes.
+- Os *reducers* (redutores) devem ser puros.
+- Cada ação descreve uma única interação do usuário.
+- Use o Immer se você deseja escrever *reducers* (redutores) de forma mutante.
-#### Dispatch actions from event handlers {/*dispatch-actions-from-event-handlers*/}
+#### Despachar *actions* (ações) a partir de *event handlers* (manipuladores de eventos) {/*dispatch-actions-from-event-handlers*/}
-Currently, the event handlers in `ContactList.js` and `Chat.js` have `// TODO` comments. This is why typing into the input doesn't work, and clicking on the buttons doesn't change the selected recipient.
+Atualmente, os *event handlers* (manipuladores de eventos) em `ContactList.js` e `Chat.js` têm comentários `// TODO`. É por isso que digitar na entrada não funciona, e clicar nos botões não altera o destinatário selecionado.
-Replace these two `// TODO`s with the code to `dispatch` the corresponding actions. To see the expected shape and the type of the actions, check the reducer in `messengerReducer.js`. The reducer is already written so you won't need to change it. You only need to dispatch the actions in `ContactList.js` and `Chat.js`.
+Substitua esses dois `// TODO`s pelo código para `dispatch` (despachar) as ações correspondentes. Para ver a forma esperada e o tipo das ações, verifique o *reducer* (redutor) em `messengerReducer.js`. O *reducer* (redutor) já está escrito, então você não precisará alterá-lo. Você só precisa despachar as ações em `ContactList.js` e `Chat.js`.
-The `dispatch` function is already available in both of these components because it was passed as a prop. So you need to call `dispatch` with the corresponding action object.
+A função `dispatch` já está disponível em ambos os componentes porque foi passada como uma *prop*. Portanto, você precisa chamar `dispatch` com o objeto de ação correspondente.
-To check the action object shape, you can look at the reducer and see which `action` fields it expects to see. For example, the `changed_selection` case in the reducer looks like this:
+Para verificar a forma do objeto de ação, você pode olhar para o *reducer* (redutor) e ver quais campos `action` ele espera ver. Por exemplo, o caso `changed_selection` no *reducer* (redutor) se parece com isto:
```js
case 'changed_selection': {
@@ -1120,7 +1120,7 @@ case 'changed_selection': {
}
```
-This means that your action object should have a `type: 'changed_selection'`. You also see the `action.contactId` being used, so you need to include a `contactId` property into your action.
+Isso significa que seu objeto de ação deve ter um `type: 'changed_selection'`. Você também vê o `action.contactId` sendo usado, então você precisa incluir uma propriedade `contactId` em sua ação.
@@ -1185,98 +1185,7 @@ export function messengerReducer(state, action) {
throw Error('Unknown action: ' + action.type);
}
}
-}
-```
-
-```js src/ContactList.js
-export default function ContactList({contacts, selectedId, dispatch}) {
- return (
-
-
- {contacts.map((contact) => (
-
-
-
- ))}
-
-
- );
-}
-```
-
-```js src/Chat.js
-import { useState } from 'react';
-
-export default function Chat({contact, message, dispatch}) {
- return (
-
-
- );
-}
-```
-
-```css
-.chat,
-.contact-list {
- float: left;
- margin-bottom: 20px;
-}
-ul,
-li {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-li button {
- width: 100px;
- padding: 10px;
- margin-right: 10px;
-}
-textarea {
- height: 150px;
-}
-```
-
-
-
-
-
-From the reducer code, you can infer that actions need to look like this:
-
-```js
-// When the user presses "Alice"
-dispatch({
- type: 'changed_selection',
- contactId: 1,
-});
-
-// When user types "Hello!"
-dispatch({
- type: 'edited_message',
- message: 'Hello!',
-});
-```
-
-Here is the example updated to dispatch the corresponding messages:
-
-
-
-```js src/App.js
+}```js src/App.js
import { useReducer } from 'react';
import Chat from './Chat.js';
import ContactList from './ContactList.js';
@@ -1284,7 +1193,7 @@ import { initialState, messengerReducer } from './messengerReducer';
export default function Messenger() {
const [state, dispatch] = useReducer(messengerReducer, initialState);
- const message = state.message;
+ const message = state.messages[state.selectedId] ?? '';
const contact = contacts.find((c) => c.id === state.selectedId);
return (
@@ -1313,7 +1222,9 @@ const contacts = [
```js src/messengerReducer.js
export const initialState = {
selectedId: 0,
- message: 'Hello',
+ messages: {
+ 0: 'Hello, Taylor!',
+ },
};
export function messengerReducer(state, action) {
@@ -1322,13 +1233,24 @@ export function messengerReducer(state, action) {
return {
...state,
selectedId: action.contactId,
- message: '',
};
}
case 'edited_message': {
return {
...state,
- message: action.message,
+ messages: {
+ ...state.messages,
+ [state.selectedId]: action.message,
+ },
+ };
+ }
+ case 'sent_message': {
+ return {
+ ...state,
+ messages: {
+ ...state.messages,
+ [state.selectedId]: '',
+ },
};
}
default: {
@@ -1362,7 +1284,7 @@ export default function ContactList({contacts, selectedId, dispatch}) {
}
```
-```js src/Chat.js
+```js src/Chat.js active
import { useState } from 'react';
export default function Chat({contact, message, dispatch}) {
@@ -1379,7 +1301,15 @@ export default function Chat({contact, message, dispatch}) {
}}
/>
-
+
);
}
@@ -1408,302 +1338,191 @@ textarea {
```
+```
+## IDs dos Títulos
-
-
-#### Clear the input on sending a message {/*clear-the-input-on-sending-a-message*/}
-
-Currently, pressing "Send" doesn't do anything. Add an event handler to the "Send" button that will:
-
-1. Show an `alert` with the recipient's email and the message.
-2. Clear the message input.
+Este documento descreve as regras que devem ser aplicadas para **todos** os idiomas.
+Quando estiver se referindo ao próprio `React`, use `o React`.
-
+## IDs dos Títulos
-```js src/App.js
-import { useReducer } from 'react';
-import Chat from './Chat.js';
-import ContactList from './ContactList.js';
-import { initialState, messengerReducer } from './messengerReducer';
-
-export default function Messenger() {
- const [state, dispatch] = useReducer(messengerReducer, initialState);
- const message = state.message;
- const contact = contacts.find((c) => c.id === state.selectedId);
- return (
-
-
-
-
- );
-}
+Todos os títulos possuem IDs explícitos como abaixo:
-const contacts = [
- {id: 0, name: 'Taylor', email: 'taylor@mail.com'},
- {id: 1, name: 'Alice', email: 'alice@mail.com'},
- {id: 2, name: 'Bob', email: 'bob@mail.com'},
-];
+```md
+## Tente React {#try-react}
```
-```js src/messengerReducer.js
-export const initialState = {
- selectedId: 0,
- message: 'Hello',
-};
-
-export function messengerReducer(state, action) {
- switch (action.type) {
- case 'changed_selection': {
- return {
- ...state,
- selectedId: action.contactId,
- message: '',
- };
- }
- case 'edited_message': {
- return {
- ...state,
- message: action.message,
- };
- }
- default: {
- throw Error('Unknown action: ' + action.type);
- }
- }
-}
-```
+**Não** traduza estes IDs! Eles são usado para navegação e quebrarão se o documento for um link externo, como:
-```js src/ContactList.js
-export default function ContactList({contacts, selectedId, dispatch}) {
- return (
-
-
- {contacts.map((contact) => (
-
-
-
- ))}
-
-
- );
-}
+```md
+Veja a [seção iniciando](/getting-started#try-react) para mais informações.
```
-```js src/Chat.js active
-import { useState } from 'react';
-
-export default function Chat({contact, message, dispatch}) {
- return (
-
-
- );
-}
-```
+✅ FAÇA:
-```css
-.chat,
-.contact-list {
- float: left;
- margin-bottom: 20px;
-}
-ul,
-li {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-li button {
- width: 100px;
- padding: 10px;
- margin-right: 10px;
-}
-textarea {
- height: 150px;
-}
+```md
+## Tente React {#try-react}
```
-
+❌ NÃO FAÇA:
-
+```md
+## Tente React {#tente-react}
+```
-There are a couple of ways you could do it in the "Send" button event handler. One approach is to show an alert and then dispatch an `edited_message` action with an empty `message`:
+Isto quebraria o link acima.
-
+## Texto em Blocos de Código
-```js src/App.js
-import { useReducer } from 'react';
-import Chat from './Chat.js';
-import ContactList from './ContactList.js';
-import { initialState, messengerReducer } from './messengerReducer';
+Mantenha o texto em blocos de código sem tradução, exceto para os comentários. Você pode optar por traduzir o texto em strings, mas tenha cuidado para não traduzir strings que se refiram ao código!
-export default function Messenger() {
- const [state, dispatch] = useReducer(messengerReducer, initialState);
- const message = state.message;
- const contact = contacts.find((c) => c.id === state.selectedId);
- return (
-
;
+// "root" se refere a um ID de elemento.
+// NÃO TRADUZA
+ReactDOM.render(element, document.getElementById('raiz'));
+```
-This works and clears the input when you hit "Send".
+❌ DEFINITIVAMENTE NÃO FAÇA:
-However, _from the user's perspective_, sending a message is a different action than editing the field. To reflect that, you could instead create a _new_ action called `sent_message`, and handle it separately in the reducer:
+```js
+// Exemplo
+const elemento =
Olá mundo
;
+ReactDOM.renderizar(elemento, documento.obterElementoPorId('raiz'));
+```
+
+## Links Externos
+
+Se um link externo se referir a um artigo no [MDN] or [Wikipedia] e se houver uma versão traduzida em seu idioma em uma qualidade decente, opte por usar a versão traduzida.
+
+[mdn]: https://developer.mozilla.org/pt-BR/
+[wikipedia]: https://pt.wikipedia.org/wiki/Wikipédia:Página_principal
+
+Exemplo:
+
+```md
+React elements are [immutable](https://en.wikipedia.org/wiki/Immutable_object).
+```
+
+✅ OK:
+
+```md
+Elementos React são [imutáveis](https://pt.wikipedia.org/wiki/Objeto_imutável).
+```
+
+Para links que não possuem tradução (Stack Overflow, vídeos do YouTube, etc.), simplesmente use o link original.
+
+## Traduções Comuns
+
+Sugestões de palavras e termos:
+
+| Palavra/Termo original | Sugestão |
+| ---------------------- | -------------------------------------- |
+| assertion | asserção |
+| at the top level | na raiz |
+| browser | navegador |
+| bubbling | propagar |
+| bug | erro |
+| caveats | ressalvas |
+| class component | componente de classe |
+| class | classe |
+| client | cliente |
+| client-side | lado do cliente |
+| container | contêiner |
+| context | contexto |
+| controlled component | componente controlado |
+| debugging | depuração |
+| DOM node | nó do DOM |
+| event handler | manipulador de eventos (event handler) |
+| function component | componente de função |
+| handler | manipulador |
+| helper function | função auxiliar |
+| high-order components | componente de alta-ordem |
+| key | chave |
+| library | biblioteca |
+| lowercase | minúscula(s) / caixa baixa |
+| package | pacote |
+| React element | Elemento React |
+| React fragment | Fragmento React |
+| render | renderizar (verb), renderizado (noun) |
+| server | servidor |
+| server-side | lado do servidor |
+| siblings | irmãos |
+| stateful component | componente com estado |
+| stateful logic | lógica com estado |
+| to assert | afirmar |
+| to wrap | encapsular |
+| troubleshooting | solução de problemas |
+| uncontrolled component | componente não controlado |
+| uppercase | maiúscula(s) / caixa alta |
+
+## Conteúdo que não deve ser traduzido
+
+- array
+- arrow function
+- bind
+- bundle
+- bundler
+- callback
+- camelCase
+- DOM
+- event listener
+- framework
+- hook
+- log
+- mock
+- portal
+- props
+- ref
+- release
+- script
+- single-page-apps
+- state
+- string
+- string literal
+- subscribe
+- subscription
+- template literal
+- timestamps
+- UI
+- watcher
+- widgets
+- wrapper
+
+## Parte 3: Atualizando componentes com `useReducer`
+
+Você já aprendeu como `useReducer` deixa a lógica do estado do componente totalmente explícita. Agora, vamos aprender a reorganizar o código para atualizar vários campos de estado (como o `selectedId` e a mensagem de chat) em um único componente usando `useReducer`.
+
+### Uma mensagem por contato {/*one-message-per-contact*/}
+
+Atualmente, o componente Mensageiro (Messenger) rastreia apenas uma única mensagem de chat. É uma string `message` na raiz do `state` de um componente. Ele atualiza o controle de textarea e envia a mensagem toda vez que você digita.
@@ -1741,7 +1560,7 @@ const contacts = [
];
```
-```js src/messengerReducer.js active
+```js src/messengerReducer.js
export const initialState = {
selectedId: 0,
message: 'Hello',
@@ -1799,7 +1618,7 @@ export default function ContactList({contacts, selectedId, dispatch}) {
}
```
-```js src/Chat.js active
+```js src/Chat.js
import { useState } from 'react';
export default function Chat({contact, message, dispatch}) {
@@ -1854,44 +1673,82 @@ textarea {
-The resulting behavior is the same. But keep in mind that action types should ideally describe "what the user did" rather than "how you want the state to change". This makes it easier to later add more features.
+O problema com essa abordagem é que só pode haver **uma** mensagem de chat. Você perderá a mensagem antiga se selecionar um contato diferente. Para corrigir isso, você precisa armazenar uma mensagem separada para cada contato.
-With either solution, it's important that you **don't** place the `alert` inside a reducer. The reducer should be a pure function--it should only calculate the next state. It should not "do" anything, including displaying messages to the user. That should happen in the event handler. (To help catch mistakes like this, React will call your reducers multiple times in Strict Mode. This is why, if you put an alert in a reducer, it fires twice.)
+### Armazenando mensagens por ID do contato {/*storing-messages-by-contact-id*/}
-
-
-#### Restore input values when switching between tabs {/*restore-input-values-when-switching-between-tabs*/}
-
-In this example, switching between different recipients always clears the text input:
+Em vez de ter um campo `message` que armazena o texto da mensagem do chat, você mudará `state` para ter um campo `messages`. O campo `messages` será um objeto com as IDs dos contatos como chaves.
```js
-case 'changed_selection': {
- return {
- ...state,
- selectedId: action.contactId,
- message: '' // Clears the input
- };
-```
-
-This is because you don't want to share a single message draft between several recipients. But it would be better if your app "remembered" a draft for each contact separately, restoring them when you switch contacts.
-
-Your task is to change the way the state is structured so that you remember a separate message draft _per contact_. You would need to make a few changes to the reducer, the initial state, and the components.
+// Antes
+const [state, dispatch] = useReducer(messengerReducer, {
+ selectedId: 0,
+ message: 'Hello, Taylor',
+});
-
+// Depois
+const [state, dispatch] = useReducer(messengerReducer, {
+ selectedId: 0,
+ messages: {
+ 0: 'Hello, Taylor',
+ 1: 'Hello, Alice',
+ 2: 'Hello, Bob',
+ },
+});
+```
-You can structure your state like this:
+Para iniciar você, modifique o `initialState` no seu arquivo `messengerReducer.js`:
```js
export const initialState = {
selectedId: 0,
messages: {
- 0: 'Hello, Taylor', // Draft for contactId = 0
- 1: 'Hello, Alice', // Draft for contactId = 1
+ 0: 'Hello, Taylor',
+ 1: 'Hello, Alice',
+ 2: 'Hello, Bob',
},
};
```
-The `[key]: value` [computed property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names) syntax can help you update the `messages` object:
+Você precisa alterar o estado de várias maneiras:
+
+* Quando o componente `Messenger` renderiza, ele precisa fornecer a mensagem **atual** para o contato selecionado.
+* Quando o usuário edita o campo de texto, você precisa atualizar a mensagem para **o contato selecionado**.
+* Quando o usuário envia uma mensagem, você precisa limpar a mensagem para **o contato selecionado**.
+
+Você pode atualizar o valor do estado `message` dentro do `App.js`:
+
+```js
+const message = state.message;
+```
+
+para ler a mensagem do estado:
+
+```js
+const message = state.messages[state.selectedId];
+```
+
+Você pode atualizar o seu reducer:
+
+```js
+// Quando a entrada for editada
+case 'edited_message': {
+ return {
+ // Mantenha outro estado como a seleção
+ ...state,
+ messages: {
+ // Mantenha mensagens para outros contatos
+ ...state.messages,
+ // Mas altere a mensagem do contato selecionado
+ [state.selectedId]: action.message
+ }
+ };
+}
+```
+
+
+
+A sintaxe de `[chave]: valor` [propriedade computada](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names) pode ajudá-lo a atualizar o objeto `messages`:
```js
{
@@ -2053,31 +1910,31 @@ textarea {
-You'll need to update the reducer to store and update a separate message draft per contact:
+Você precisará atualizar o reducer para armazenar e atualizar um rascunho de mensagem separado por contato:
```js
-// When the input is edited
+// Quando a entrada for editada
case 'edited_message': {
return {
- // Keep other state like selection
+ // Mantenha outro estado como a seleção
...state,
messages: {
- // Keep messages for other contacts
+ // Mantenha mensagens para outros contatos
...state.messages,
- // But change the selected contact's message
+ // Mas altere a mensagem do contato selecionado
[state.selectedId]: action.message
}
};
}
```
-You would also update the `Messenger` component to read the message for the currently selected contact:
+Você também atualizaria o componente `Messenger` para ler a mensagem do contato selecionado atualmente:
```js
const message = state.messages[state.selectedId];
```
-Here is the complete solution:
+Aqui está a solução completa:
@@ -2237,19 +2094,19 @@ textarea {
-Notably, you didn't need to change any of the event handlers to implement this different behavior. Without a reducer, you would have to change every event handler that updates the state.
+Notavelmente, você não precisou alterar nenhum dos manipuladores de eventos para implementar esse comportamento diferente. Sem um reducer, você teria que alterar todos os manipuladores de eventos que atualizam o estado.
-#### Implement `useReducer` from scratch {/*implement-usereducer-from-scratch*/}
+#### Implemente `useReducer` do zero {/*implement-usereducer-from-scratch*/}
-In the earlier examples, you imported the `useReducer` Hook from React. This time, you will implement _the `useReducer` Hook itself!_ Here is a stub to get you started. It shouldn't take more than 10 lines of code.
+Nos exemplos anteriores, você importou o Hook `useReducer` do React. Desta vez, você implementará _o próprio Hook `useReducer`!_ Aqui está um stub para começar. Não deve demorar mais de 10 linhas de código.
-To test your changes, try typing into the input or select a contact.
+Para testar suas alterações, tente digitar na entrada ou selecionar um contato.
-Here is a more detailed sketch of the implementation:
+Aqui está um esboço mais detalhado da implementação:
```js
export function useReducer(reducer, initialState) {
@@ -2263,7 +2120,7 @@ export function useReducer(reducer, initialState) {
}
```
-Recall that a reducer function takes two arguments--the current state and the action object--and it returns the next state. What should your `dispatch` implementation do with it?
+Lembre-se que uma função reducer recebe dois argumentos --o estado atual e o objeto de ação-- e retorna o próximo estado. O que sua implementação `dispatch` deve fazer com ele?
@@ -2439,7 +2296,7 @@ textarea {
-Dispatching an action calls a reducer with the current state and the action, and stores the result as the next state. This is what it looks like in code:
+A transmissão de uma ação chama um reducer com o estado atual e a ação, e armazena o resultado como o estado seguinte. É assim que fica no código:
@@ -2614,7 +2471,7 @@ textarea {
-Though it doesn't matter in most cases, a slightly more accurate implementation looks like this:
+Embora não importe na maioria dos casos, uma implementação um pouco mais precisa é assim:
```js
function dispatch(action) {
@@ -2622,8 +2479,6 @@ function dispatch(action) {
}
```
-This is because the dispatched actions are queued until the next render, [similar to the updater functions.](/learn/queueing-a-series-of-state-updates)
+Isso ocorre porque as ações enviadas são enfileiradas até a próxima renderização, [semelhante às funções de atualização.](/learn/queueing-a-series-of-state-updates)
-
-