feat: add 'back/front end' in curriculum (#42596)

* chore: rename APIs and Microservices to include "Backend" (#42515)

* fix typo

* fix typo

* undo change

* Corrected grammar mistake

Corrected a grammar mistake by removing a comma.

* change APIs and Microservices cert title

* update title

* Change APIs and Microservices certi title

* Update translations.json

* update title

* feat(curriculum): rename apis and microservices cert

* rename folder structure

* rename certificate

* rename learn Markdown

* apis-and-microservices -> back-end-development-and-apis

* update backend meta

* update i18n langs and cypress test

Co-authored-by: Shaun Hamilton <shauhami020@gmail.com>

* fix: add development to front-end libraries (#42512)

* fix: added-the-word-Development-to-front-end-libraries

* fix/added-the-word-Development-to-front-end-libraries

* fix/added-word-development-to-front-end-libraries-in-other-related-files

* fix/added-the-word-Development-to-front-end-and-all-related-files

* fix/removed-typos-from-last-commit-in-index.md

* fix/reverted-changes-that-i-made-to-dependecies

* fix/removed xvfg

* fix/reverted changes that i made to package.json

* remove unwanted changes

* front-end-development-libraries changes

* rename backend certSlug and README

* update i18n folder names and keys

* test: add legacy path redirect tests

This uses serve.json from the client-config repo, since we currently use
that in production

* fix: create public dir before moving serve.json

* fix: add missing script

* refactor: collect redirect tests

* test: convert to cy.location for stricter tests

* rename certificate folder to 00-certificates

* change crowdin config to recognise new certificates location

* allow translations to be used

Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>

* add forwards slashes to path redirects

* fix cypress path tests again

* plese cypress

* fix: test different challenge

Okay so I literally have no idea why this one particular challenge
fails in Cypress Firefox ONLY. Tom and I paired and spun a full build
instance and confirmed in Firefox the page loads and redirects as
expected. Changing to another bootstrap challenge passes Cypress firefox
locally. Absolutely boggled by this.

AAAAAAAAAAAAAAA

* fix: separate the test

Okay apparently the test does not work unless we separate it into
a different `it` statement.

>:( >:( >:( >:(

Co-authored-by: Sujal Gupta <55016909+heysujal@users.noreply.github.com>
Co-authored-by: Noor Fakhry <65724923+NoorFakhry@users.noreply.github.com>
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Nicholas Carrigan (he/him) <nhcarrigan@gmail.com>
This commit is contained in:
Shaun Hamilton
2021-08-14 03:57:13 +01:00
committed by GitHub
parent 4df2a0c542
commit c2a11ad00d
1215 changed files with 790 additions and 449 deletions

View File

@ -0,0 +1,175 @@
---
id: 5a24c314108439a4d4036154
title: Combinare reducers multipli
challengeType: 6
forumTopicId: 301436
dashedName: combine-multiple-reducers
---
# --description--
Quando lo stato della tua app comincia a diventare più complesso, potresti essere tentato di dividere lo stato in più parti. Ricorda invece il primo principio di Redux: tutto lo stato dell'app è tenuto in un singolo oggetto di stato nello store. Detto questo, Redux fornisce la composizione di reducers come soluzione per un modello di stato complesso. Definisci più reducer per gestire diverse parti dello stato della tua applicazione, quindi componi questi reducer insieme in un root reducer (riduttore radice). Il root reducer viene quindi passato nel metodo Redux `createStore()`.
Per farci combinare più reducer insieme, Redux fornisce il metodo `combineReducers()`. Questo metodo accetta come argomento un oggetto in cui si definiscono le proprietà che associano le chiavi a specifiche funzioni reducer. Il nome dato alle chiavi sarà usato da Redux come nome per la parte di stato associata.
Tipicamente, è una buona pratica creare un reducer per ogni parte dello stato dell'applicazione quando essi sono distinti o unici in qualche modo. Ad esempio, in un'applicazione per prende appunti con autenticazione dell'utente, un reducer potrebbe gestire l'autenticazione mentre un altro gestisce il testo e le note che l'utente sta scrivendo. Per tale applicazione, potremmo scrivere il metodo `combineReducers()` in questo modo:
```js
const rootReducer = Redux.combineReducers({
auth: authenticationReducer,
notes: notesReducer
});
```
Ora, la chiave `notes` conterrà tutto lo stato associato alle nostre note e gestito dal nostro `notesReducer`. Questo è il modo in cui più reducer possono essere composti per gestire uno stato dell'applicazione più complesso. In questo esempio, lo stato mantenuto nello store di Redux sarebbe quindi un singolo oggetto contenente le proprietà `auth` e `notes`.
# --instructions--
Nell'editor di codice trovi le funzioni `counterReducer()` e `authReducer()`, insieme a uno store di Redux. Completa la funzione `rootReducer()` usando il metodo `Redux.combineReducers()`. Assegna `counterReducer` a una chiave denominata `count` e `authReducer` a una chiave denominata `auth`.
# --hints--
Il `counterReducer` dovrebbe aumentare e diminuire lo `state`.
```js
assert(
(function () {
const initialState = store.getState().count;
store.dispatch({ type: INCREMENT });
store.dispatch({ type: INCREMENT });
const firstState = store.getState().count;
store.dispatch({ type: DECREMENT });
const secondState = store.getState().count;
return firstState === initialState + 2 && secondState === firstState - 1;
})()
);
```
`authReducer` dovrebbe commutare lo `state` di `authenticated` tra `true` e `false`.
```js
assert(
(function () {
store.dispatch({ type: LOGIN });
const loggedIn = store.getState().auth.authenticated;
store.dispatch({ type: LOGOUT });
const loggedOut = store.getState().auth.authenticated;
return loggedIn === true && loggedOut === false;
})()
);
```
Lo `state` dello store dovrebbe avere due chiavi: `count`, che contiene un numero, e `auth`, che contiene un oggetto. L'oggetto `auth` dovrebbe avere una proprietà `authenticated`, che contiene un booleano.
```js
assert(
(function () {
const state = store.getState();
return (
typeof state.auth === 'object' &&
typeof state.auth.authenticated === 'boolean' &&
typeof state.count === 'number'
);
})()
);
```
Il `rootReducer` dovrebbe essere una funzione che combina il `counterReducer` e l'`authReducer`.
```js
(getUserInput) =>
assert(
(function () {
const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index'));
return (
typeof rootReducer === 'function' &&
noWhiteSpace.includes('Redux.combineReducers')
);
})()
);
```
# --seed--
## --seed-contents--
```js
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const counterReducer = (state = 0, action) => {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
const LOGIN = 'LOGIN';
const LOGOUT = 'LOGOUT';
const authReducer = (state = {authenticated: false}, action) => {
switch(action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const rootReducer = // Define the root reducer here
const store = Redux.createStore(rootReducer);
```
# --solutions--
```js
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const counterReducer = (state = 0, action) => {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
const LOGIN = 'LOGIN';
const LOGOUT = 'LOGOUT';
const authReducer = (state = {authenticated: false}, action) => {
switch(action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const rootReducer = Redux.combineReducers({
count: counterReducer,
auth: authReducer
});
const store = Redux.createStore(rootReducer);
```

View File

@ -0,0 +1,133 @@
---
id: 5a24c314108439a4d403615b
title: Copiare un oggetto con Object.assign
challengeType: 6
forumTopicId: 301437
dashedName: copy-an-object-with-object-assign
---
# --description--
Le ultime sfide funzionavano con gli array, ma ci sono modi per aiutare a far rispettare l'immutabilità dello stato anche quando esso è un `object`. Uno strumento utile per gestire gli oggetti è l'utilità `Object.assign()`. `Object.assign()` prende un oggetto di destinazione e degli oggetti di origine e mappa le proprietà dagli oggetti di origine all'oggetto di destinazione. Tutte le proprietà corrispondenti sono sovrascritte dalle proprietà degli oggetti sorgente. Questo comportamento è comunemente usato per fare copie superficiali di oggetti passando un oggetto vuoto come primo argomento seguito dall'oggetto o dagli oggetti che si desidera copiare. Ecco un esempio:
```js
const newObject = Object.assign({}, obj1, obj2);
```
Questo crea `newObject` come nuovo `object`, che contiene le proprietà che attualmente esistono in `obj1` e `obj2`.
# --instructions--
Lo stato di Redux e le azioni sono state modificate per gestire un `object` per lo `state`. Modifica il codice per restituire un nuovo oggetto `state` per le azioni di tipo `ONLINE`, che imposta la proprietà `status` sulla stringa `online`. Prova a usare `Object.assign()` per completare la sfida.
# --hints--
Lo store Redux dovrebbe esistere ed essere inizializzato con uno stato equivalente all'oggetto `defaultState` dichiarato alla riga 1.
```js
assert(
(function () {
const expectedState = {
user: 'CamperBot',
status: 'offline',
friends: '732,982',
community: 'freeCodeCamp'
};
const initialState = store.getState();
return DeepEqual(expectedState, initialState);
})()
);
```
`wakeUp` e `immutableReducer` dovrebbero essere entrambe funzioni.
```js
assert(typeof wakeUp === 'function' && typeof immutableReducer === 'function');
```
L'invio di un'azione di tipo `ONLINE` dovrebbe aggiornare la proprietà `status` allo stato `online` e NON dovrebbe mutare lo stato.
```js
assert(
(function () {
const initialState = store.getState();
const isFrozen = DeepFreeze(initialState);
store.dispatch({ type: 'ONLINE' });
const finalState = store.getState();
const expectedState = {
user: 'CamperBot',
status: 'online',
friends: '732,982',
community: 'freeCodeCamp'
};
return isFrozen && DeepEqual(finalState, expectedState);
})()
);
```
`Object.assign` dovrebbe essere usato per restituire il nuovo stato.
```js
(getUserInput) => assert(getUserInput('index').includes('Object.assign'));
```
# --seed--
## --seed-contents--
```js
const defaultState = {
user: 'CamperBot',
status: 'offline',
friends: '732,982',
community: 'freeCodeCamp'
};
const immutableReducer = (state = defaultState, action) => {
switch(action.type) {
case 'ONLINE':
// Don't mutate state here or the tests will fail
return
default:
return state;
}
};
const wakeUp = () => {
return {
type: 'ONLINE'
}
};
const store = Redux.createStore(immutableReducer);
```
# --solutions--
```js
const defaultState = {
user: 'CamperBot',
status: 'offline',
friends: '732,982',
community: 'freeCodeCamp'
};
const immutableReducer = (state = defaultState, action) => {
switch(action.type) {
case 'ONLINE':
return Object.assign({}, state, {
status: 'online'
});
default:
return state;
}
};
const wakeUp = () => {
return {
type: 'ONLINE'
}
};
const store = Redux.createStore(immutableReducer);
```

View File

@ -0,0 +1,61 @@
---
id: 5a24c314108439a4d403614b
title: Creare uno store di Redux
challengeType: 6
forumTopicId: 301439
dashedName: create-a-redux-store
---
# --description--
Redux è un framework di gestione dello stato che può essere utilizzato con una serie di diverse tecnologie web, tra cui React.
In Redux c'è un singolo oggetto di stato che è responsabile per l'intero stato della tua applicazione. Ciò significa che se hai un'app React con dieci componenti, e ogni componente aveva il proprio stato locale, l'intero stato della tua app sarà definito da un singolo oggetto di stato ospitato nello `store` di Redux. Questo è il primo principio importante da capire quando si studia Redux: lo store di Redux è la singola fonte di verità quando si tratta di stato dell'applicazione.
Questo significa anche che ogni volta che una parte della tua app vuole aggiornare lo stato, essa **deve** farlo attraverso lo store di Redux. Il flusso di dati unidirezionale rende più facile monitorare la gestione dello stato nella tua app.
# --instructions--
Lo `store` di Redux è un oggetto che detiene e gestisce lo `state` dell'applicazione. Nell'oggetto Redux c'è un metodo chiamato `createStore()` che si usa per creare lo `store` di Redux. Questo metodo prende una funzione `reducer` come argomento richiesto. La funzione `reducer` è spiegata da una sfida successiva, ed è già definita per te nell'editor di codice. Essa richiede semplicemente `state` come argomento e restituisce `state`.
Dichiara una variabile `store` e assegnala al metodo `createStore()`, passando il `reducer` come argomento.
**Nota:** Il codice nell'editor utilizza la sintassi predefinita degli argomenti ES6 per inizializzare questo stato in modo da contenere un valore di `5`. Se non hai familiarità con gli argomenti predefiniti, puoi fare riferimento alla [sezione ES6 nel Curriculum](https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/set-default-parameters-for-your-functions) che copre questo argomento.
# --hints--
Lo store di Redux dovrebbe esistere.
```js
assert(typeof store.getState === 'function');
```
Lo store di Redux dovrebbe avere un valore di 5 per lo stato.
```js
assert(store.getState() === 5);
```
# --seed--
## --seed-contents--
```js
const reducer = (state = 5) => {
return state;
}
// Redux methods are available from a Redux object
// For example: Redux.createStore()
// Define the store here:
```
# --solutions--
```js
const reducer = (state = 5) => {
return state;
}
const store = Redux.createStore(reducer);
```

View File

@ -0,0 +1,55 @@
---
id: 5a24c314108439a4d403614d
title: Definire un'azione Redux
challengeType: 6
forumTopicId: 301440
dashedName: define-a-redux-action
---
# --description--
Dal momento che Redux è un framework di gestione dello stato, l'aggiornamento dello stato è uno dei suoi compiti fondamentali. In Redux, tutti gli aggiornamenti di stato vengono attivati dalle azioni di dispatching (invio). Un'azione è semplicemente un oggetto JavaScript che contiene informazioni su un evento di azione che si è verificato. Lo store Redux riceve questi oggetti di azione, quindi aggiorna il suo stato di conseguenza. A volte un'azione Redux contiene anche dei dati. Ad esempio, l'azione contiene uno username dopo il login di un utente. Mentre i dati sono facoltativi, le azioni devono contenere una proprietà `type` che specifica il 'tipo' di azione che si è verificato.
Pensa alle azioni Redux come a messaggeri che portano informazioni sugli eventi che accadono nella tua app allo store di Redux. Lo store conduce poi l'attività di aggiornamento dello stato in base all'azione che si è verificata.
# --instructions--
Scrivere un'azione Redux è semplice come dichiarare un oggetto con una proprietà type. Dichiara un oggetto `action` e dagli una proprietà `type` impostata alla stringa `'LOGIN'`.
# --hints--
Dovrebbe esistere un oggetto `action`.
```js
assert(
(function () {
return typeof action === 'object';
})()
);
```
L'oggetto `action` dovrebbe avere una proprietà `type` con valore `LOGIN`.
```js
assert(
(function () {
return action.type === 'LOGIN';
})()
);
```
# --seed--
## --seed-contents--
```js
// Define an action here:
```
# --solutions--
```js
const action = {
type: 'LOGIN'
}
```

View File

@ -0,0 +1,57 @@
---
id: 5a24c314108439a4d403614e
title: Definire un creatore di azione
challengeType: 6
forumTopicId: 301441
dashedName: define-an-action-creator
---
# --description--
Dopo aver creato un'azione, il passo successivo è l'invio dell'azione allo store di Redux in modo che possa aggiornare il suo stato. Per farlo, in Redux si definiscono i creatori di azione. Un creatore di azione è semplicemente una funzione JavaScript che restituisce un'azione. In altre parole, i creatori di azione creano oggetti che rappresentano gli eventi di azione.
# --instructions--
Definisci una funzione `actionCreator()` che restituisce l'oggetto `action` quando chiamata.
# --hints--
La funzione `actionCreator` dovrebbe esistere.
```js
assert(typeof actionCreator === 'function');
```
L'esecuzione della funzione `actionCreator` dovrebbe restituire l'oggetto `action`.
```js
assert(typeof action === 'object');
```
L'`action` restituita dovrebbe avere una proprietà di chiave `type` con valore `LOGIN`.
```js
assert(action.type === 'LOGIN');
```
# --seed--
## --seed-contents--
```js
const action = {
type: 'LOGIN'
}
// Define an action creator here:
```
# --solutions--
```js
const action = {
type: 'LOGIN'
}
const actionCreator = () => {
return action;
};
```

View File

@ -0,0 +1,85 @@
---
id: 5a24c314108439a4d403614f
title: Inviare un evento azione
challengeType: 6
forumTopicId: 301442
dashedName: dispatch-an-action-event
---
# --description--
Il metodo `dispatch` è quello che usi per inviare azioni allo store Redux. Chiamando `store.dispatch()` e passando il valore restituito da un creatore di azione, un'azione viene inviata di rimando allo store.
Ricorda che i creatori di azione restituiscono un oggetto con una proprietà type che specifica l'azione che si è verificata. Quindi il metodo invia un oggetto di azione allo store di Redux. Sulla base dell'esempio della sfida precedente, le seguenti righe sono equivalenti, ed entrambe inviano l'azione di tipo `LOGIN`:
```js
store.dispatch(actionCreator());
store.dispatch({ type: 'LOGIN' });
```
# --instructions--
Lo store Redux nell'editor di codice ha uno stato inizializzato con un oggetto contenente una proprietà `login`, attualmente impostata a `false`. C'è anche un creatore di azione denominato `loginAction()` che restituisce un'azione di tipo `LOGIN`. Invia l'azione `LOGIN` allo store Redux chiamando il metodo `dispatch`, e passandole l'azione creata da `loginAction()`.
# --hints--
Chiamare la funzione `loginAction` dovrebbe restituire un oggetto con la proprietà `type` impostata alla stringa `LOGIN`.
```js
assert(loginAction().type === 'LOGIN');
```
Lo store dovrebbe essere inizializzato con un oggetto con proprietà `login` impostata su `false`.
```js
assert(store.getState().login === false);
```
Il metodo `store.dispatch()` dovrebbe essere utilizzato per inviare un'azione di tipo `LOGIN`.
```js
(getUserInput) =>
assert(
(function () {
let noWhiteSpace = getUserInput('index').replace(/\s/g, '');
return (
noWhiteSpace.includes('store.dispatch(loginAction())') ||
noWhiteSpace.includes("store.dispatch({type: 'LOGIN'})") === true
);
})()
);
```
# --seed--
## --seed-contents--
```js
const store = Redux.createStore(
(state = {login: false}) => state
);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
// Dispatch the action here:
```
# --solutions--
```js
const store = Redux.createStore(
(state = {login: false}) => state
);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
store.dispatch(loginAction());
```

View File

@ -0,0 +1,55 @@
---
id: 5a24c314108439a4d403614c
title: Ottenere lo stato dallo store di Redux
challengeType: 6
forumTopicId: 301443
dashedName: get-state-from-the-redux-store
---
# --description--
L'oggetto store di Redux fornisce diversi metodi che consentono di interagire con esso. Ad esempio, è possibile recuperare lo `state` attuale contenuto nell'oggetto store di Redux con il metodo `getState()`.
# --instructions--
Il codice della sfida precedente viene riscritto più concisamente nell'editor di codice. Usa `store.getState()` per recuperare lo `state` dallo `store`, e assegnarlo a una nuova variabile `currentState`.
# --hints--
Lo store di Redux dovrebbe avere un valore di 5 come stato iniziale.
```js
assert(store.getState() === 5);
```
Una variabile `currentState` dovrebbe esistere e dovrebbe esserle assegnato lo stato corrente dello store di Redux.
```js
(getUserInput) =>
assert(
currentState === 5 && getUserInput('index').includes('store.getState()')
);
```
# --seed--
## --seed-contents--
```js
const store = Redux.createStore(
(state = 5) => state
);
// Change code below this line
```
# --solutions--
```js
const store = Redux.createStore(
(state = 5) => state
);
// Change code below this line
const currentState = store.getState();
```

View File

@ -0,0 +1,108 @@
---
id: 5a24c314108439a4d4036150
title: Gestire un'azione nello store
challengeType: 6
forumTopicId: 301444
dashedName: handle-an-action-in-the-store
---
# --description--
Dopo che un'azione è stata creata e spedita, lo store di Redux deve sapere come rispondere a quell'azione. Questo è il lavoro di una funzione `reducer` (riduttore). I reducer in Redux sono responsabili delle modifiche allo stato che si verificano in risposta alle azioni. Un `reducer` prende `state` e `action` come argomenti, e restituisce sempre un nuovo `state`. È importante capire che questo è l'**unico** ruolo del reducer. Questo non ha effetti collaterali - non chiama mai un endpoint API e non ha mai sorprese nascoste. Il reducer è semplicemente una funzione pura che prende uno stato e un'azione, e restituisce un nuovo stato.
Un altro principio chiave in Redux è che lo `state` è di sola lettura. In altre parole, la funzione `reducer` deve **sempre** restituire una nuova copia dello `state` e non modificare mai direttamente lo state. Redux non applica l'immutabilità dello stato, tuttavia sei responsabile di applicarlo nel codice delle tue funzioni reducer. Nelle prossime sfide farai pratica con questo.
# --instructions--
L'editor di codice contiene l'esempio precedente e l'inizio di una funzione `reducer` pronti per te. Compila il corpo della funzione `reducer` in modo che se riceve un'azione di tipo `'LOGIN'` restituisca un oggetto stato con `login` impostato a `true`. Altrimenti, restituisce lo `state` attuale. Nota che lo `state` corrente e l'`action` inviata sono passati al reducer, in modo da poter accedere direttamente al tipo di azione con `action.type`.
# --hints--
Chiamare la funzione `loginAction` dovrebbe restituire un oggetto con proprietà type impostata sulla stringa `LOGIN`.
```js
assert(loginAction().type === 'LOGIN');
```
Lo store dovrebbe essere inizializzato con un oggetto con proprietà `login` impostata su `false`.
```js
assert(store.getState().login === false);
```
Inviare `loginAction` dovrebbe aggiornare la proprietà `login` nello stato dello store a `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginAction());
const afterState = store.getState();
return initialState.login === false && afterState.login === true;
})()
);
```
Se l'azione non è di tipo `LOGIN`, lo store dovrebbe restituire lo stato corrente.
```js
assert(
(function () {
store.dispatch({ type: '__TEST__ACTION__' });
let afterTest = store.getState();
return typeof afterTest === 'object' && afterTest.hasOwnProperty('login');
})()
);
```
# --seed--
## --seed-contents--
```js
const defaultState = {
login: false
};
const reducer = (state = defaultState, action) => {
// Change code below this line
// Change code above this line
};
const store = Redux.createStore(reducer);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
```
# --solutions--
```js
const defaultState = {
login: false
};
const reducer = (state = defaultState, action) => {
if (action.type === 'LOGIN') {
return {login: true}
}
else {
return state
}
};
const store = Redux.createStore(reducer);
const loginAction = () => {
return {
type: 'LOGIN'
}
};
```

View File

@ -0,0 +1,133 @@
---
id: 5a24c314108439a4d4036158
title: Mai mutare lo stato
challengeType: 6
forumTopicId: 301445
dashedName: never-mutate-state
---
# --description--
Queste ultime sfide descrivono diversi metodi per far rispettare il principio fondamentale dell'immutabilità dello stato in Redux. Immutabilità dello stato significa che non si modifica mai direttamente lo stato, ma si restituisce una nuova copia di esso.
Se scattassi un'istantanea dello stato di un'applicazione Redux nel tempo, vedresti qualcosa come `state 1`, `state 2`, `state 3`,`state 4`, `...` e così via dove ogni stato può essere simile al precedente, ma ognuno è un dato distinto. Questa immutabilità, infatti, è ciò che fornisce caratteristiche come il debugging time-travel (viaggio nel tempo) di cui potresti aver sentito parlare.
Redux non applica attivamente l'immutabilità dello stato nel suo store o nei reducer: questa responsabilità ricade sul programmatore. Fortunatamente, JavaScript (specialmente ES6) fornisce diversi strumenti utili che puoi usare per far rispettare l'immutabilità del tuo stato, che si tratti di una `string`, `number`, `array` o `object`. Nota che le stringhe e i numeri sono valori primitivi e sono immutabili per natura. In altre parole, 3 è sempre 3. Non è possibile modificare il valore del numero 3. Un `array` o `object`, invece, è mutabile. In pratica, il tuo stato sarà probabilmente costituito da un `array` o da un `object`, trattandosi di strutture di dati utili per rappresentare molti tipi di informazioni.
# --instructions--
Nell'editor di codice ci sono uno `store` e un `reducer` per gestire gli elementi della lista to-do. Termina la scrittura del caso `ADD_TO_DO` nel reducer per aggiungere una nuova cosa da fare allo stato. Ci sono alcuni modi per realizzarlo con standard JavaScript o ES6. Vedi se puoi trovare un modo per restituire un nuovo array con l'elemento preso da `action.todo` aggiunto alla fine.
# --hints--
Lo store Redux dovrebbe esistere ed essere inizializzato con uno stato uguale all'array `todos` nell'editor di codice.
```js
assert(
(function () {
const todos = [
'Go to the store',
'Clean the house',
'Cook dinner',
'Learn to code'
];
const initialState = store.getState();
return (
Array.isArray(initialState) && initialState.join(',') === todos.join(',')
);
})()
);
```
`addToDo` e `immutableReducer` dovrebbero essere entrambe funzioni.
```js
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
```
L'invio di un'azione di tipo `ADD_TO_DO` allo store di Redux dovrebbe aggiungere un elemento `todo` e NON dovrebbe mutare lo stato.
```js
assert(
(function () {
const initialState = store.getState();
const isFrozen = DeepFreeze(initialState);
store.dispatch(addToDo('__TEST__TO__DO__'));
const finalState = store.getState();
const expectedState = [
'Go to the store',
'Clean the house',
'Cook dinner',
'Learn to code',
'__TEST__TO__DO__'
];
return isFrozen && DeepEqual(finalState, expectedState);
})()
);
```
# --seed--
## --seed-contents--
```js
const ADD_TO_DO = 'ADD_TO_DO';
// A list of strings representing tasks to do:
const todos = [
'Go to the store',
'Clean the house',
'Cook dinner',
'Learn to code',
];
const immutableReducer = (state = todos, action) => {
switch(action.type) {
case ADD_TO_DO:
// Don't mutate state here or the tests will fail
return
default:
return state;
}
};
const addToDo = (todo) => {
return {
type: ADD_TO_DO,
todo
}
}
const store = Redux.createStore(immutableReducer);
```
# --solutions--
```js
const ADD_TO_DO = 'ADD_TO_DO';
const todos = [
'Go to the store',
'Clean the house',
'Cook dinner',
'Learn to code',
];
const immutableReducer = (state = todos, action) => {
switch(action.type) {
case ADD_TO_DO:
return state.concat(action.todo);
default:
return state;
}
};
const addToDo = (todo) => {
return {
type: ADD_TO_DO,
todo
}
}
const store = Redux.createStore(immutableReducer);
```

View File

@ -0,0 +1,118 @@
---
id: 5a24c314108439a4d4036153
title: Registrare un listener dello store
challengeType: 6
forumTopicId: 301446
dashedName: register-a-store-listener
---
# --description--
Un altro metodo a cui hai accesso dall'oggetto `store` di Redux è `store.subscribe()`. Questo ti permette di iscrivere delle funzioni listener (di ascolto) nello store, che vengono chiamate ogni volta che un'azione viene spedita allo store. Un semplice utilizzo per questo metodo è quello di iscrivere una funzione al tuo store, in modo che registri semplicemente un messaggio ogni volta che un'azione viene ricevuta e lo store viene aggiornato.
# --instructions--
Scrivi una funzione di callback che incrementa la variabile globale `count` ogni volta che lo store riceve un'azione, e passa questa funzione al metodo `store.subscribe()`. Vedrai che `store.dispatch()` è chiamato tre volte di fila, ogni volta che passa direttamente in un oggetto azione. Guarda l'output della console tra le azioni inviate per vedere gli aggiornamenti effettuati.
# --hints--
La spedizione dell'azione `ADD` allo store dovrebbe aumentare lo stato di `1`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch({ type: 'ADD' });
const newState = store.getState();
return newState === initialState + 1;
})()
);
```
Dovrebbe esserci una funzione listener iscritta allo store usando `store.subscribe`.
```js
(getUserInput) => assert(getUserInput('index').match(/store\s*\.\s*subscribe\(/gm));
```
`store.subscribe` dovrebbe ricevere una funzione.
```js
(getUserInput) => assert(getUserInput('index').match(/(\s*function\s*)|(\s*\(\s*\)\s*=>)/gm))
```
La callback `store.subscribe` dovrebbe anche aumentare la variabile globale `count` quando lo store viene aggiornato.
```js
assert(store.getState() === count);
```
# --seed--
## --before-user-code--
```js
count = 0;
```
## --seed-contents--
```js
const ADD = 'ADD';
const reducer = (state = 0, action) => {
switch(action.type) {
case ADD:
return state + 1;
default:
return state;
}
};
const store = Redux.createStore(reducer);
// Global count variable:
let count = 0;
// Change code below this line
// Change code above this line
store.dispatch({type: ADD});
console.log(count);
store.dispatch({type: ADD});
console.log(count);
store.dispatch({type: ADD});
console.log(count);
```
# --solutions--
```js
const ADD = 'ADD';
const reducer = (state = 0, action) => {
switch(action.type) {
case ADD:
return state + 1;
default:
return state;
}
};
const store = Redux.createStore(reducer);
let count = 0;
// Change code below this line
store.subscribe( () =>
{
count++;
}
);
// Change code above this line
store.dispatch({type: ADD});
store.dispatch({type: ADD});
store.dispatch({type: ADD});
```

View File

@ -0,0 +1,114 @@
---
id: 5a24c314108439a4d403615a
title: Rimuovere un elemento da un Array
challengeType: 6
forumTopicId: 301447
dashedName: remove-an-item-from-an-array
---
# --description--
È ora di fare pratica con la rimozione di elementi da un array. L'operatore di propagazione può essere utilizzato anche qui. Altri utili metodi JavaScript includono `slice()` e `concat()`.
# --instructions--
Il reducer e il creatore di azione sono stati modificati per rimuovere un elemento da un array in base all'indice dell'elemento. Termina la scrittura del reducer in modo che un nuovo array di stato venga restituito senza l'elemento all'indice specificato.
# --hints--
Lo store di Redux dovrebbe esistere ed essere inizializzato con uno stato uguale a `[0,1,2,3,4,5]`
```js
assert(
(function () {
const initialState = store.getState();
return (
Array.isArray(initialState) === true &&
DeepEqual(initialState, [0, 1, 2, 3, 4, 5])
);
})()
);
```
`removeItem` e `immutableReducer` dovrebbero essere entrambe funzioni.
```js
assert(
typeof removeItem === 'function' && typeof immutableReducer === 'function'
);
```
La spedizione del creatore di azione `removeItem` dovrebbe rimuovere gli elementi dallo stato e NON dovrebbe mutare lo stato.
```js
assert(
(function () {
const initialState = store.getState();
const isFrozen = DeepFreeze(initialState);
store.dispatch(removeItem(3));
const state_1 = store.getState();
store.dispatch(removeItem(2));
const state_2 = store.getState();
store.dispatch(removeItem(0));
store.dispatch(removeItem(0));
store.dispatch(removeItem(0));
const state_3 = store.getState();
return (
isFrozen &&
DeepEqual(state_1, [0, 1, 2, 4, 5]) &&
DeepEqual(state_2, [0, 1, 4, 5]) &&
DeepEqual(state_3, [5])
);
})()
);
```
# --seed--
## --seed-contents--
```js
const immutableReducer = (state = [0,1,2,3,4,5], action) => {
switch(action.type) {
case 'REMOVE_ITEM':
// Don't mutate state here or the tests will fail
return
default:
return state;
}
};
const removeItem = (index) => {
return {
type: 'REMOVE_ITEM',
index
}
}
const store = Redux.createStore(immutableReducer);
```
# --solutions--
```js
const immutableReducer = (state = [0,1,2,3,4,5], action) => {
switch(action.type) {
case 'REMOVE_ITEM':
return [
...state.slice(0, action.index),
...state.slice(action.index + 1)
];
default:
return state;
}
};
const removeItem = (index) => {
return {
type: 'REMOVE_ITEM',
index
}
}
const store = Redux.createStore(immutableReducer);
```

View File

@ -0,0 +1,107 @@
---
id: 5a24c314108439a4d4036155
title: Inviare i dati delle azioni allo store
challengeType: 6
forumTopicId: 301448
dashedName: send-action-data-to-the-store
---
# --description--
Finora hai imparato come inviare azioni allo store Redux, ma queste azioni non contenevano alcuna informazione diversa da un `type`. Puoi anche inviare dati specifici insieme alle tue azioni. In realtà, questo è molto comune perché le azioni di solito provengono da alcune interazioni dell'utente e tendono a portare dei dati con loro. Lo store di Redux ha spesso bisogno di conoscere questi dati.
# --instructions--
Nell'editor di codice ci sono un `notesReducer()` di base e un creatore di azione `addNoteText()`. Termina il corpo della funzione `addNoteText()` in modo che restituisca un oggetto `action`. L'oggetto dovrebbe includere una proprietà `type` con un valore di `ADD_NOTE`, e anche una proprietà `text` impostata al dato `note` passato al creatore di azione. Quando chiami il creatore di azione, passi specifiche informazioni alle quali puoi accedere per l'oggetto.
Successivamente, termina la scrittura dell'istruzione `switch` in `notesReducer()`. Dovrai aggiungere un caso che gestisca le azioni `addNoteText()`. Questo caso dovrebbe essere attivato ogni volta che c'è un'azione di tipo `ADD_NOTE` e dovrebbe restituire la proprietà `text` dell'`action` in arrivo come nuovo `state`.
L'azione viene spedita nella parte finale del codice. Una volta finito, esegui il codice e guarda la console. Questo è tutto ciò che serve per inviare dati specifici dell'azione allo store e usarli quando aggiorni lo `state` dello store.
# --hints--
Il creatore di azioni `addNoteText` dovrebbe restituire un oggetto con chiavi `type` e `text`.
```js
assert(
(function () {
const addNoteFn = addNoteText('__TEST__NOTE');
return addNoteFn.type === ADD_NOTE && addNoteFn.text === '__TEST__NOTE';
})()
);
```
La spedizione di un'azione di tipo `ADD_NOTE` con il creatore di azione `addNoteText` dovrebbe aggiornare lo `state` alla stringa passata al creatore dell'azione.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(addNoteText('__TEST__NOTE'));
const newState = store.getState();
return initialState !== newState && newState === '__TEST__NOTE';
})()
);
```
# --seed--
## --seed-contents--
```js
const ADD_NOTE = 'ADD_NOTE';
const notesReducer = (state = 'Initial State', action) => {
switch(action.type) {
// Change code below this line
// Change code above this line
default:
return state;
}
};
const addNoteText = (note) => {
// Change code below this line
// Change code above this line
};
const store = Redux.createStore(notesReducer);
console.log(store.getState());
store.dispatch(addNoteText('Hello!'));
console.log(store.getState());
```
# --solutions--
```js
const ADD_NOTE = 'ADD_NOTE';
const notesReducer = (state = 'Initial State', action) => {
switch(action.type) {
// Change code below this line
case ADD_NOTE:
return action.text;
// Change code above this line
default:
return state;
}
};
const addNoteText = (note) => {
// Change code below this line
return {
type: ADD_NOTE,
text: note
}
// Change code above this line
};
const store = Redux.createStore(notesReducer);
console.log(store.getState());
store.dispatch(addNoteText('Hello Redux!'));
console.log(store.getState());
```

View File

@ -0,0 +1,152 @@
---
id: 5a24c314108439a4d4036151
title: Usare un'istruzione switch per gestire più azioni
challengeType: 6
forumTopicId: 301449
dashedName: use-a-switch-statement-to-handle-multiple-actions
---
# --description--
È possibile dire allo store di Redux come gestire diversi tipi di azione. Diciamo che tu debba gestire l'autenticazione dell'utente nel tuo store di Redux. Vuoi avere una rappresentazione dello stato per quando gli utenti sono connessi e per quando sono disconnessi. Lo rappresenti con un singolo oggetto di stato con la proprietà `authenticated`. Hai anche bisogno di creatori di azione che creino azioni corrispondenti al login e al logout dell'utente, insieme agli oggetti azione stessi.
# --instructions--
L'editor di codice ha già uno store, delle azioni e dei creatori di azioni configurati per te. Completa la funzione `reducer` perché gestisca più azioni di autenticazione. Usa un'istruzione JavaScript `switch` nel `reducer` per rispondere a diversi eventi di azione. Questo è un modello standard nella scrittura di reducer Redux. L'istruzione switch dovrebbe smistare in base a `action.type` e restituire lo stato di autenticazione appropriato.
**Nota:** Non preoccuparti per l'immutabilità dello stato, dato che è piccolo e semplice in questo esempio. Per ogni azione, puoi restituire un nuovo oggetto — per esempio, `{authenticated: true}`. Inoltre, non dimenticare di scrivere un caso di `default` nella tua istruzione switch che restituisca lo `state` corrente. Questo è importante perché una volta che l'app ha più reducer, essi vengono eseguiti tutti ogni volta che viene spedita un'azione, anche quando l'azione non è correlata a quel reducer. In questo caso, vuoi assicurarti di restituire lo `state` corrente.
# --hints--
Chiamando la funzione `loginUser` dovrebbe essere restituito un oggetto con proprietà type impostata alla stringa `LOGIN`.
```js
assert(loginUser().type === 'LOGIN');
```
Chiamando la funzione `logoutUser` dovrebbe essere restituito un oggetto con proprietà type impostata alla stringa `LOGOUT`.
```js
assert(logoutUser().type === 'LOGOUT');
```
Lo store dovrebbe essere inizializzato con un oggetto con una proprietà `authenticated` impostata a `false`.
```js
assert(store.getState().authenticated === false);
```
L'invio di `loginUser` dovrebbe impostare a `true` la proprietà `authenticated` nello stato dello store.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginUser());
const afterLogin = store.getState();
return (
initialState.authenticated === false && afterLogin.authenticated === true
);
})()
);
```
La spedizione di `logoutUser` dovrebbe impostare a `false` la proprietà `authenticated` nello stato dello store.
```js
assert(
(function () {
store.dispatch(loginUser());
const loggedIn = store.getState();
store.dispatch(logoutUser());
const afterLogout = store.getState();
return (
loggedIn.authenticated === true && afterLogout.authenticated === false
);
})()
);
```
La funzione `authReducer` dovrebbe gestire più tipi di azione con un'istruzione `switch`.
```js
(getUserInput) =>
assert(
getUserInput('index').toString().includes('switch') &&
getUserInput('index').toString().includes('case') &&
getUserInput('index').toString().includes('default')
);
```
# --seed--
## --seed-contents--
```js
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
// Change code below this line
// Change code above this line
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: 'LOGIN'
}
};
const logoutUser = () => {
return {
type: 'LOGOUT'
}
};
```
# --solutions--
```js
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
switch (action.type) {
case 'LOGIN':
return {
authenticated: true
}
case 'LOGOUT':
return {
authenticated: false
}
default:
return state;
}
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: 'LOGIN'
}
};
const logoutUser = () => {
return {
type: 'LOGOUT'
}
};
```

View File

@ -0,0 +1,205 @@
---
id: 5a24c314108439a4d4036152
title: Usare const per i tipi di azione
challengeType: 6
forumTopicId: 301450
dashedName: use-const-for-action-types
---
# --description--
Una pratica comune quando si lavora con Redux è quella di assegnare i tipi di azione come costanti di sola lettura, quindi fare riferimento a queste costanti ovunque siano usate. Puoi rivedere il codice con cui stai lavorando per scrivere i tipi di azione come dichiarazioni `const`.
# --instructions--
Dichiara `LOGIN` e `LOGOUT` come valori `const` e assegnali rispettivamente alle stringhe `'LOGIN'` e `'LOGOUT'`. Quindi, modifica `authReducer()` e i creatori di azione in modo che facciano riferimento a queste costanti invece che ai valori stringa.
**Nota:** È una convenzione generale scrivere le costanti tutte in maiuscolo e questa è la pratica standard anche in Redux.
# --hints--
Chiamando la funzione `loginUser` dovrebbe essere restituito un oggetto con la proprietà `type` impostata alla stringa `LOGIN`.
```js
assert(loginUser().type === 'LOGIN');
```
Chiamando la funzione `logoutUser` dovrebbe essere restituito un oggetto con la proprietà `type` impostata alla stringa `LOGOUT`.
```js
assert(logoutUser().type === 'LOGOUT');
```
Lo store dovrebbe essere inizializzato con un oggetto con proprietà `login` impostata su `false`.
```js
assert(store.getState().authenticated === false);
```
Il dispatch di `loginUser` dovrebbe impostare a `true` la proprietà `login` nello stato dello store.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginUser());
const afterLogin = store.getState();
return (
initialState.authenticated === false && afterLogin.authenticated === true
);
})()
);
```
Il dispatch di `logoutUser` dovrebbe impostare a `false` la proprietà `login` nello stato dello store.
```js
assert(
(function () {
store.dispatch(loginUser());
const loggedIn = store.getState();
store.dispatch(logoutUser());
const afterLogout = store.getState();
return (
loggedIn.authenticated === true && afterLogout.authenticated === false
);
})()
);
```
La funzione `authReducer` dovrebbe gestire più tipi di azione con un'istruzione switch.
```js
(getUserInput) =>
assert(
(function () {
return (
typeof authReducer === 'function' &&
getUserInput('index').toString().includes('switch') &&
getUserInput('index').toString().includes('case') &&
getUserInput('index').toString().includes('default')
);
})()
);
```
`LOGIN` e `LOGOUT` dovrebbero essere dichiarati come valori `const` e dovrebbero essere assegnate loro le stringhe `LOGIN` e `LOGOUT`.
```js
const noWhiteSpace = __helpers.removeWhiteSpace(code);
assert(
(/constLOGIN=(['"`])LOGIN\1/.test(noWhiteSpace) &&
/constLOGOUT=(['"`])LOGOUT\1/.test(noWhiteSpace)) ||
/const(LOGIN|LOGOUT)=(['"`])\1\2,(?!\1)(LOGIN|LOGOUT)=(['"`])\3\4/.test(noWhiteSpace)
);
```
I creatori di azioni e il reducer dovrebbero fare riferimento alle costanti `LOGIN` e `LOGOUT`.
```js
(getUserInput) =>
assert(
(function () {
const noWhiteSpace = __helpers.removeWhiteSpace(
getUserInput('index').toString()
);
return (
noWhiteSpace.includes('caseLOGIN:') &&
noWhiteSpace.includes('caseLOGOUT:') &&
noWhiteSpace.includes('type:LOGIN') &&
noWhiteSpace.includes('type:LOGOUT')
);
})()
);
```
# --seed--
## --seed-contents--
```js
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
switch (action.type) {
case 'LOGIN':
return {
authenticated: true
}
case 'LOGOUT':
return {
authenticated: false
}
default:
return state;
}
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: 'LOGIN'
}
};
const logoutUser = () => {
return {
type: 'LOGOUT'
}
};
```
# --solutions--
```js
const LOGIN = 'LOGIN';
const LOGOUT = 'LOGOUT';
const defaultState = {
authenticated: false
};
const authReducer = (state = defaultState, action) => {
switch (action.type) {
case LOGIN:
return {
authenticated: true
}
case LOGOUT:
return {
authenticated: false
}
default:
return state;
}
};
const store = Redux.createStore(authReducer);
const loginUser = () => {
return {
type: LOGIN
}
};
const logoutUser = () => {
return {
type: LOGOUT
}
};
```

View File

@ -0,0 +1,170 @@
---
id: 5a24c314108439a4d4036156
title: Usare il middleware per gestire azioni asincrone
challengeType: 6
forumTopicId: 301451
dashedName: use-middleware-to-handle-asynchronous-actions
---
# --description--
Finora queste sfide hanno evitato di discutere di azioni asincrone, ma esse sono una parte inevitabile dello sviluppo del web. Ad un certo punto dovrai chiamare gli endpoint asincroni nell'app Redux, quindi come gestirai questi tipi di richiesta? Redux fornisce un middleware (software di intermediazione) progettato specificamente per questo scopo, chiamato Redux Thunk middleware. Ecco una breve descrizione di come usarlo con Redux.
Per includere il Redux Thunk middleware, lo passi come argomento a `Redux.applyMiddleware()`. Questa istruzione viene quindi fornita come secondo parametro opzionale alla funzione `createStore()`. Dai un'occhiata al codice in fondo all'editor per vederlo. Poi, per creare un'azione asincrona, restituisci una funzione nel creatore di azione che richiede `dispatch` come argomento. All'interno di questa funzione, è possibile inviare azioni ed eseguire richieste asincrone.
In questo esempio, una richiesta asincrona viene simulata con una chiamata `setTimeout()`. È comune inviare un'azione prima di iniziare qualsiasi comportamento asincrono in modo che lo stato dell'applicazione sappia che sono stati richiesti alcuni dati (questo stato potrebbe mostrare un'icona di caricamento, per esempio). Poi, una volta ricevuti i dati, si invia un'altra azione che trasporta i dati come payload insieme all'informazione che l'azione è completata.
Ricorda che stai passando `dispatch` come parametro a questo creatore di azioni speciale. Questo è quello che userai per inviare le tue azioni: passerai l'azione direttamente al dispatch e il middleware si occuperà del resto.
# --instructions--
Scrivi entrambi i dispatch nel creatore di azioni `handleAsync()`. Fai un dispatch di `requestingData()` prima di `setTimeout()` (la chiamata API simulata). Poi, dopo aver ricevuto i dati (simulati), invia l'azione `receivedData()`, passando questi dati. Ora sai come gestire le azioni asincrone in Redux. Tutto il resto continua a funzionare come prima.
# --hints--
Il creatore di azione `requestingData` dovrebbe restituire un oggetto type pari al valore di `REQUESTING_DATA`.
```js
assert(requestingData().type === REQUESTING_DATA);
```
Il creatore di azione `receivedData` dovrebbe restituire un oggetto type pari al valore di `RECEIVED_DATA`.
```js
assert(receivedData('data').type === RECEIVED_DATA);
```
`asyncDataReducer` dovrebbe essere una funzione.
```js
assert(typeof asyncDataReducer === 'function');
```
Il dispatch del creatore di azione `requestingData` dovrebbe aggiornare la proprietà fetching dello `state` dello store a `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(requestingData());
const reqState = store.getState();
return initialState.fetching === false && reqState.fetching === true;
})()
);
```
Il dispatch di `handleAsync` dovrebbe inviare l'azione di richiesta di dati e quindi inviare l'azione di ricezione dei dati dopo un certo ritardo.
```js
assert(
(function () {
const noWhiteSpace = __helpers.removeWhiteSpace(handleAsync.toString());
return (
noWhiteSpace.includes('dispatch(requestingData())') === true &&
noWhiteSpace.includes('dispatch(receivedData(data))') === true
);
})()
);
```
# --seed--
## --seed-contents--
```js
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
const handleAsync = () => {
return function(dispatch) {
// Dispatch request action here
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
// Dispatch received data action here
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
```
# --solutions--
```js
const REQUESTING_DATA = 'REQUESTING_DATA'
const RECEIVED_DATA = 'RECEIVED_DATA'
const requestingData = () => { return {type: REQUESTING_DATA} }
const receivedData = (data) => { return {type: RECEIVED_DATA, users: data.users} }
const handleAsync = () => {
return function(dispatch) {
dispatch(requestingData());
setTimeout(function() {
let data = {
users: ['Jeff', 'William', 'Alice']
}
dispatch(receivedData(data));
}, 2500);
}
};
const defaultState = {
fetching: false,
users: []
};
const asyncDataReducer = (state = defaultState, action) => {
switch(action.type) {
case REQUESTING_DATA:
return {
fetching: true,
users: []
}
case RECEIVED_DATA:
return {
fetching: false,
users: action.users
}
default:
return state;
}
};
const store = Redux.createStore(
asyncDataReducer,
Redux.applyMiddleware(ReduxThunk.default)
);
```

View File

@ -0,0 +1,114 @@
---
id: 5a24c314108439a4d4036159
title: Usare l'operatore di propagazione sugli array
challengeType: 6
forumTopicId: 301452
dashedName: use-the-spread-operator-on-arrays
---
# --description--
Una soluzione di ES6 per contribuire a far rispettare l'immutabilità dello stato in Redux è l'operatore di propagazione (spred): `...`. L'operatore di propagazione ha una varietà di applicazioni, una delle quali si adatta bene alla precedente sfida di produrre un nuovo array da un array esistente. Si tratta di una sintassi relativamente nuova, ma comunemente usata. Ad esempio, se hai un array `myArray` e scrivi:
```js
let newArray = [...myArray];
```
`newArray` è ora un clone di `myArray`. Entrambi gli array esistono ancora separatamente in memoria. Se esegui una mutazione come `newArray.push(5)`, `myArray` non cambia. L'operatore `...` effettivamente *propaga* i valori di `myArray` a un nuovo array. Per clonare un array con dei valori aggiuntivi nel nuovo array, potresti scrivere `[...myArray, 'new value']`. Questo restituirebbe un nuovo array composto dai valori in `myArray` e la stringa `new value` come ultimo valore. La sintassi di propagazione può essere usata più volte in una composizione di array come questa, ma è importante notare che fa solo una copia superficiale dell'array. Vale a dire, fornisce operazioni di array immutabili solo per array unidimensionali.
# --instructions--
Usa l'operatore di propagazione per restituire una nuova copia dello stato quando viene aggiunta una cosa da fare.
# --hints--
Lo store Redux dovrebbe esistere ed essere inizializzato con uno stato uguale a `["Do not mutate state!"]`.
```js
assert(
(function () {
const initialState = store.getState();
return (
Array.isArray(initialState) === true &&
initialState[0] === 'Do not mutate state!'
);
})()
);
```
`addToDo` e `immutableReducer` dovrebbero essere entrambe funzioni.
```js
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
```
L'invio di un'azione di tipo `ADD_TO_DO` allo store di Redux dovrebbe aggiungere un elemento `todo` e NON dovrebbe mutare lo stato.
```js
assert(
(function () {
const initialState = store.getState();
const isFrozen = DeepFreeze(initialState);
store.dispatch(addToDo('__TEST__TO__DO__'));
const finalState = store.getState();
const expectedState = ['Do not mutate state!', '__TEST__TO__DO__'];
return isFrozen && DeepEqual(finalState, expectedState);
})()
);
```
L'operatore di propagazione deve essere utilizzato per restituire il nuovo stato.
```js
(getUserInput) => assert(getUserInput('index').includes('...state'));
```
# --seed--
## --seed-contents--
```js
const immutableReducer = (state = ['Do not mutate state!'], action) => {
switch(action.type) {
case 'ADD_TO_DO':
// Don't mutate state here or the tests will fail
return
default:
return state;
}
};
const addToDo = (todo) => {
return {
type: 'ADD_TO_DO',
todo
}
}
const store = Redux.createStore(immutableReducer);
```
# --solutions--
```js
const immutableReducer = (state = ['Do not mutate state!'], action) => {
switch(action.type) {
case 'ADD_TO_DO':
return [
...state,
action.todo
];
default:
return state;
}
};
const addToDo = (todo) => {
return {
type: 'ADD_TO_DO',
todo
}
}
const store = Redux.createStore(immutableReducer);
```

View File

@ -0,0 +1,116 @@
---
id: 5a24c314108439a4d4036157
title: Scrivere un contatore con Redux
challengeType: 6
forumTopicId: 301453
dashedName: write-a-counter-with-redux
---
# --description--
Ora hai imparato tutti i principi fondamentali di Redux! Hai visto come creare azioni e creatori di azioni, creare uno store di Redux, inviare le tue azioni allo store e progettare gli aggiornamenti di stato con i reducer puri. Hai visto anche come gestire uno stato complesso con la composizione di reducer e la gestione di azioni asincrone. Questi esempi sono semplicistici, ma questi concetti sono i principi fondamentali di Redux. Se li capisci bene, sei pronto a iniziare a costruire la tua app con Redux. Le prossime sfide copriranno alcuni dettagli relativi all'immutabilità dello `state`, ma prima, ecco un ripasso di tutto quello che hai imparato finora.
# --instructions--
In questa lezione, realizzerai da zero un semplice contatore con Redux. Le basi sono fornite nell'editor di codice, ma dovrai riempire i dettagli! Utilizza i nomi forniti e definisci i creatori di azione `incAction` e `decAction`, il reducer `counterReducer()`, i tipi di azione `INCREMENT` e `DECREMENT`, e infine lo `store` di Redux. Una volta terminato, dovresti essere in grado di inviare le azioni `INCREMENT` o `DECREMENT` per aumentare o diminuire lo stato mantenuto nello `store`. Buona fortuna per la costruzione della tua prima app Redux!
# --hints--
Il creatore di azioni `incAction` dovrebbe restituire un oggetto azione con `type` uguale al valore di `INCREMENT`
```js
assert(incAction().type === INCREMENT);
```
Il creatore di azione `decAction` dovrebbe restituire un oggetto azione con `type` uguale al valore di `DECREMENT`
```js
assert(decAction().type === DECREMENT);
```
Lo store Redux dovrebbe essere inizializzato con uno `state` di 0.
```js
assert(store.getState() === 0);
```
Effettuare il dispatch di `incAction` nello store Redux dovrebbe aumentare lo `state` di 1.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(incAction());
const incState = store.getState();
return initialState + 1 === incState;
})()
);
```
Effettuare il dispatch di `decAction` nello store Redux dovrebbe decrementare lo `state` di 1.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(decAction());
const decState = store.getState();
return initialState - 1 === decState;
})()
);
```
`counterReducer` dovrebbe essere una funzione
```js
assert(typeof counterReducer === 'function');
```
# --seed--
## --seed-contents--
```js
const INCREMENT = null; // Define a constant for increment action types
const DECREMENT = null; // Define a constant for decrement action types
const counterReducer = null; // Define the counter reducer which will increment or decrement the state based on the action it receives
const incAction = null; // Define an action creator for incrementing
const decAction = null; // Define an action creator for decrementing
const store = null; // Define the Redux store here, passing in your reducers
```
# --solutions--
```js
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';
const counterReducer = (state = 0, action) => {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
};
const incAction = () => {
return {
type: INCREMENT
}
};
const decAction = () => {
return {
type: DECREMENT
}
};
const store = Redux.createStore(counterReducer);
```