Skip to content

Commit 6d66467

Browse files
committed
part6c update
1 parent 5eb5ce8 commit 6d66467

File tree

1 file changed

+116
-75
lines changed

1 file changed

+116
-75
lines changed

src/content/6/es/part6c.md

Lines changed: 116 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -393,15 +393,15 @@ Modificar la creación de nuevas anécdotas, de forma que las anécdotas se alma
393393

394394
### Acciones asincrónicas y redux thunk
395395

396-
Nuestro enfoque está bien, pero no es bueno que la comunicación con el servidor ocurra dentro de las funciones de los componentes. Sería mejor si la comunicación se pudiera abstraer de los componentes, de modo que no tuvieran que hacer nada más que llamar al <i>creador de la acción</i> correspondiente. Como ejemplo, <i>App</i> inicializaría el estado de la aplicación de la siguiente manera:
396+
Nuestro enfoque es bastante bueno, pero no es genial que la comunicación con el servidor suceda dentro de las funciones de los componentes. Sería mejor si la comunicación pudiera abstraerse de los componentes para que no tengan que hacer nada más que llamar al creador de acciones apropiado. Como ejemplo, <i>App</i> inicializaría el estado de la aplicación de la siguiente manera:
397397

398398
```js
399399
const App = () => {
400400
const dispatch = useDispatch()
401401

402402
useEffect(() => {
403403
dispatch(initializeNotes())
404-
},[dispatch])
404+
}, [dispatch])
405405

406406
// ...
407407
}
@@ -424,86 +424,47 @@ const NewNote = () => {
424424
}
425425
```
426426

427-
Ambos componentes solo usarían la función que se les proporciona como prop sin importar la comunicación con el servidor que está sucediendo en segundo plano.
427+
En esta implementación, ambos componentes enviarían una acción sin necesidad de saber sobre la comunicación entre el servidor que sucede detrás de escena. Estos tipos de <i>acciones asincrónicas</i> se pueden implementar utilizando la librería [Redux Thunk](https://github.com/reduxjs/redux-thunk). El uso de la librería no requiere ninguna configuración adicional o incluso instalación cuando el store de Redux se crea utilizando la función <em>configureStore</em> del kit de herramientas de Redux (Redux Toolkit).
428428

429-
Ahora instalemos la librería [redux-thunk](https://github.com/gaearon/redux-thunk), que nos permite crear <i>acciones asincrónicas</i>. La instalación se realiza con el comando:
429+
Con Redux Thunk, es posible implementar <i>action creators</i> que devuelven una función en lugar de un objeto. La función recibe los métodos <em>dispatch</em> y <em>getState</em> del store de Redux como parámetros. Esto permite, por ejemplo, implementaciones de creadores de acciones asincrónicas, que primero esperan la finalización de una cierta operación asincrónica y luego despachan alguna acción, que cambia el estado del store.
430430

431-
```bash
432-
npm install redux-thunk
433-
```
434-
435-
La librería redux-thunk es un <i>redux-middleware</i>, que debe inicializarse junto con la inicialización del store. Mientras estamos aquí, extraigamos la definición del store en su propio archivo <i>src/store.js</i>:
431+
Podemos implementar el <i>action creator</i> <em>initializeNotes</em> que inicializa las notas basadas en los datos recibidos del servidor de la siguiente manera:
436432

437433
```js
438-
import { createStore, combineReducers, applyMiddleware } from 'redux'
439-
import thunk from 'redux-thunk' // highlight-line
440-
import { composeWithDevTools } from 'redux-devtools-extension'
441-
442-
import noteReducer from './reducers/noteReducer'
443-
import filterReducer from './reducers/filterReducer'
444-
445-
const reducer = combineReducers({
446-
notes: noteReducer,
447-
filter: filterReducer,
448-
})
449-
450-
const store = createStore(
451-
reducer,
452-
composeWithDevTools(
453-
applyMiddleware(thunk) // highlight-line
454-
)
455-
)
456-
457-
export default store
458-
```
459-
460-
Después de los cambios, el archivo <i>src/index.js</i> se ve así
461-
After the changes the file <i>src/index.js</i> looks like this
462-
463-
```js
464-
import React from 'react'
465-
import ReactDOM from 'react-dom'
466-
import { Provider } from 'react-redux'
467-
import store from './store' // highlight-line
468-
import App from './App'
469-
470-
ReactDOM.render(
471-
<Provider store={store}>
472-
<App />
473-
</Provider>,
474-
document.getElementById('root')
475-
)
476-
```
477-
478-
Gracias a redux-thunk, es posible definir <i>creadores de acciones</i> para que devuelvan una función que tenga como parámetro el método <i>dispatch</i> de redux-store. Como resultado de esto, se pueden hacer creadores de acciones asincrónicas, que primero esperan a que termine alguna operación, luego de lo cual luego envían la acción real.
434+
// ...
435+
import noteService from '../services/notes' // highlight-line
479436

437+
const noteSlice = createSlice(/* ... */)
480438

481-
Ahora podemos definir el creador de acciones, <i>initializeNotes</i>, que inicializa el estado de las notas de la siguiente manera:
439+
export const { createNote, toggleImportanceOf, setNotes, appendNote } = noteSlice.actions
482440

483-
```js
441+
// highlight-start
484442
export const initializeNotes = () => {
485443
return async dispatch => {
486444
const notes = await noteService.getAll()
487-
dispatch({
488-
type: 'INIT_NOTES',
489-
data: notes,
490-
})
445+
dispatch(setNotes(notes))
491446
}
492447
}
448+
// highlight-end
449+
450+
export default noteSlice.reducer
493451
```
494452

495-
En la función interna, es decir, la <i>acción asincrónica</i>, la operación primero obtiene todas las notas del servidor y luego envía las notas a la acción, que las agrega al store.
453+
En la función interna, es decir, la <i>acción asincrónica</i>, la operación primero obtiene todas las notas del servidor y luego <i>despacha</i> la acción <em>setNotes</em>, que las agrega al store.
496454

497-
El componente <i>App</i> ahora se puede definir de la siguiente manera:
455+
El componente <i>App</i> puede inicializar las notas de la siguiente manera:
498456

499457
```js
458+
// ...
459+
import { initializeNotes } from './reducers/noteReducer' // highlight-line
460+
500461
const App = () => {
501462
const dispatch = useDispatch()
502463

503464
// highlight-start
504465
useEffect(() => {
505466
dispatch(initializeNotes())
506-
},[dispatch])
467+
}, [dispatch])
507468
// highlight-end
508469

509470
return (
@@ -516,27 +477,71 @@ const App = () => {
516477
}
517478
```
518479

519-
La solución es elegante. La lógica de inicialización de las notas se ha separado completamente fuera del componente React.
480+
La solución es bastante elegante. La lógica de inicialización de las notas se ha separado completamente del componente React.
520481

521-
El creador de acciones _createNote_, que agrega una nueva nota tiene este aspecto
482+
Ahora, reemplacemos el creador de acciones <em>createNote</em> creado por la función <em>createSlice</em> con un creador de acciones asincrónico:
522483

523484
```js
485+
// ...
486+
import noteService from '../services/notes'
487+
488+
const noteSlice = createSlice({
489+
name: 'notes',
490+
initialState: [],
491+
reducers: {
492+
toggleImportanceOf(state, action) {
493+
const id = action.payload
494+
495+
const noteToChange = state.find(n => n.id === id)
496+
497+
const changedNote = {
498+
...noteToChange,
499+
important: !noteToChange.important
500+
}
501+
502+
return state.map(note =>
503+
note.id !== id ? note : changedNote
504+
)
505+
},
506+
appendNote(state, action) {
507+
state.push(action.payload)
508+
},
509+
setNotes(state, action) {
510+
return action.payload
511+
}
512+
// createNote definition removed from here!
513+
},
514+
})
515+
516+
export const { toggleImportanceOf, appendNote, setNotes } = noteSlice.actions // highlight-line
517+
518+
export const initializeNotes = () => {
519+
return async dispatch => {
520+
const notes = await noteService.getAll()
521+
dispatch(setNotes(notes))
522+
}
523+
}
524+
525+
// highlight-start
524526
export const createNote = content => {
525527
return async dispatch => {
526528
const newNote = await noteService.createNew(content)
527-
dispatch({
528-
type: 'NEW_NOTE',
529-
data: newNote,
530-
})
529+
dispatch(appendNote(newNote))
531530
}
532531
}
532+
// highlight-end
533+
534+
export default noteSlice.reducer
533535
```
534536

535-
El principio aquí es el mismo: primero se ejecuta una operación asincrónica, después de lo cual se envía la acción que cambia el estado del store.
537+
El principio aquí es el mismo: primero se ejecuta una operación asincrónica y luego se <i>despacha</i> la acción que cambia el estado del store.
536538

537-
El componente <i>NewNote</i> cambia de la siguiente manera:
539+
El componente <i>NewNote</i> cambia como se muestra a continuación:
538540

539541
```js
542+
// ...
543+
import { createNote } from '../reducers/noteReducer' // highlight-line
544+
540545
const NewNote = () => {
541546
const dispatch = useDispatch()
542547

@@ -550,35 +555,71 @@ const NewNote = () => {
550555
return (
551556
<form onSubmit={addNote}>
552557
<input name="note" />
553-
<button type="submit">lisää</button>
558+
<button type="submit">add</button>
554559
</form>
555560
)
556561
}
557562
```
558563

559-
El estado actual del código para la aplicación se puede encontrar en [github](https://github.com/fullstack-hy2020/redux-notes/tree/part6-4) en la rama <i>part6-4</i>.
564+
Finalmente, limpiemos un poco el archivo <i>index.js</i> moviendo el código relacionado con la creación del store de Redux a su propio archivo <i>store.js</i>:
565+
566+
```js
567+
import { configureStore } from '@reduxjs/toolkit'
568+
569+
import noteReducer from './reducers/noteReducer'
570+
import filterReducer from './reducers/filterReducer'
571+
572+
const store = configureStore({
573+
reducer: {
574+
notes: noteReducer,
575+
filter: filterReducer
576+
}
577+
})
578+
579+
export default store
580+
```
581+
582+
Despues de los cambios, el contenido del archivo <i>index.js</i> es el siguiente:
583+
584+
```js
585+
import React from 'react'
586+
import ReactDOM from 'react-dom/client'
587+
import { Provider } from 'react-redux'
588+
import store from './store' // highlight-line
589+
import App from './App'
590+
591+
ReactDOM.createRoot(document.getElementById('root')).render(
592+
<Provider store={store}>
593+
<App />
594+
</Provider>
595+
)
596+
```
597+
598+
El estado actual del código de la aplicación se puede encontrar en [GitHub](https://github.com/fullstack-hy2020/redux-notes/tree/part6-5) en la rama <i>part6-5</i>.
599+
600+
Redux Toolkit ofrece una gran cantidad de herramientas para simplificar la administración de estado asíncrono. Las herramientas adecuadas para este caso de uso son, por ejemplo, la función [createAsyncThunk](https://redux-toolkit.js.org/api/createAsyncThunk) y la API [RTK Query](https://redux-toolkit.js.org/rtk-query/overview).
560601

561602
</div>
562603

563604
<div class="tasks">
564605

565606

566-
### Ejercicios 6.15.-6.18.
607+
### Ejercicios 6.16.-6.19.
567608

568-
#### 6.15 Anécdotas y el backend, paso3
609+
#### 6.16 Anécdotas y el backend, paso 3
569610

570-
Modifique la inicialización de redux-store para que suceda utilizando creadores de acciones asincrónicas, que son posibles gracias a la librería <i>redux-thunk</i>.
611+
Modifique la inicialización de la redux-store para que suceda utilizando creadores de acciones asincrónicas, que son posibles gracias a la librería <i>redux-thunk</i>.
571612

572-
#### 6.16 Anécdotas y el backend, paso 4
613+
#### 6.17 Anécdotas y el backend, paso 4
573614

574615
También modifique la creación de una nueva anécdota para que suceda usando creadores de acciones asincrónicas, hecho posible por la librería <i>redux-thunk</i>.
575616

576617

577-
#### 6.17 Anécdotas y el backend, paso 5
618+
#### 6.18 Anécdotas y el backend, paso 5
578619

579620
La votación aún no guarda los cambios en el backend. Arregle la situación con la ayuda de la librería <i>redux-thunk</i>.
580621

581-
#### 6.18 Anécdotas y el backend, paso 6
622+
#### 6.19 Anécdotas y el backend, paso 6
582623

583624
La creación de notificaciones sigue siendo un poco tediosa, ya que hay que realizar dos acciones y utilizar la función _setTimeout_:
584625

0 commit comments

Comments
 (0)