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,156 @@
---
id: 5a24c314108439a4d4036147
title: Connettere Redux a React
challengeType: 6
forumTopicId: 301426
dashedName: connect-redux-to-react
---
# --description--
Ora che hai scritto sia la funzione `mapStateToProps()` che la funzione `mapDispatchToProps()`, puoi utilizzarle per mappare lo `state` e spedirlo (`dispatch`) alle `props` di uno dei tuoi componenti React. Il metodo `connect` può gestire questa attività per passare i dati da React a Redux. Questo metodo richiede due argomenti opzionali, `mapStateToProps()` e `mapDispatchToProps()`. Sono opzionali perché potresti avere un componente che ha bisogno solo di accedere allo `state` ma non ha bisogno di inviare alcuna azione, o viceversa.
Per usare questo metodo, passa le funzioni come argomenti, e chiama immediatamente il risultato con il tuo componente. Questa sintassi è un po' insolita e appare così:
```js
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
```
**Nota:** Se vuoi omettere uno degli argomenti del metodo `connect`, passa `null` al loro posto.
# --instructions--
L'editor di codice contiene le funzioni `mapStateToProps()` e `mapDispatchToProps()` e un nuovo componente React chiamato `Presentational`. Collega questo componente a Redux con il metodo `connect` dall'oggetto globale `ReactRedux`, e chiamalo immediatamente sul componente `Presentational`. Assegna il risultato a una nuova `const` chiamata `ConnectedComponent` che rappresenta il componente collegato. Questo è tutto, ora sei connesso a Redux! Prova a impostare uno dei due argomenti di `connect` a `null` e osserva i risultati del test.
# --hints--
Il componente `Presentational` dovrebbe effettuare il render.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('Presentational').length === 1;
})()
);
```
Il componente `Presentational` dovrebbe ricevere una prop `messages` via `connect`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const props = mockedComponent.find('Presentational').props();
return props.messages === '__INITIAL__STATE__';
})()
);
```
Il componente `Presentational` dovrebbe ricevere una prop `submitNewMessage` via `connect`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const props = mockedComponent.find('Presentational').props();
return typeof props.submitNewMessage === 'function';
})()
);
```
# --seed--
## --after-user-code--
```jsx
const store = Redux.createStore(
(state = '__INITIAL__STATE__', action) => state
);
class AppWrapper extends React.Component {
render() {
return (
<ReactRedux.Provider store = {store}>
<ConnectedComponent/>
</ReactRedux.Provider>
);
}
};
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
```
## --seed-contents--
```jsx
const addMessage = (message) => {
return {
type: 'ADD',
message: message
}
};
const mapStateToProps = (state) => {
return {
messages: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message));
}
}
};
class Presentational extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h3>This is a Presentational Component</h3>
}
};
const connect = ReactRedux.connect;
// Change code below this line
```
# --solutions--
```jsx
const addMessage = (message) => {
return {
type: 'ADD',
message: message
}
};
const mapStateToProps = (state) => {
return {
messages: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message));
}
}
};
class Presentational extends React.Component {
constructor(props) {
super(props);
}
render() {
return <h3>This is a Presentational Component</h3>
}
};
const connect = ReactRedux.connect;
// Change code below this line
const ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Presentational);
```

View File

@ -0,0 +1,300 @@
---
id: 5a24c314108439a4d4036148
title: Connettere Redux all'app Messaggi
challengeType: 6
forumTopicId: 301427
dashedName: connect-redux-to-the-messages-app
---
# --description--
Ora che sai come usare `connect` per connettere React a Redux, puoi applicare quello che hai imparato al tuo componente React che gestisce i messaggi.
Nell'ultima lezione, il componente che hai collegato a Redux è stato chiamato `Presentational`, e questo non è stato arbitrario. Questo termine *generalmente* si riferisce a componenti React che non sono direttamente collegati a Redux. Sono semplicemente responsabili della presentazione dell'interfaccia utente e fanno questo in funzione delle props che ricevono. Al contrario, i componenti contenitore sono collegati a Redux. Essi sono tipicamente responsabili della spedizione delle azioni allo store e spesso passano lo stato dello store ai componenti figli come props.
# --instructions--
L'editor di codice contiene tutto il codice che hai scritto finora in questa sezione. L'unico cambiamento è che il componente React è stato rinominato in `Presentational`. Crea un nuovo componente memorizzato in una costante chiamata `Container` che utilizza `connect` per collegare il componente `Presentational` a Redux. Poi, in `AppWrapper`, presenta il componente React Redux `Provider`. Passa a `Provider` lo `store` di Redux come una prop e presenta `Container` come figlio. Una volta che sarà tutto configurato, vedrai nuovamente l'app dei messaggi presentata nella pagina.
# --hints--
L' `AppWrapper` dovrebbe essere presentata nella pagina.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('AppWrapper').length === 1;
})()
);
```
Il componente `Presentational` dovrebbe essere presentato nella pagina.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('Presentational').length === 1;
})()
);
```
Il componente `Presentational` dovrebbe fare il render degli elementi `h2`, `input`, `button`e `ul`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
return (
PresentationalComponent.find('div').length === 1 &&
PresentationalComponent.find('h2').length === 1 &&
PresentationalComponent.find('button').length === 1 &&
PresentationalComponent.find('ul').length === 1
);
})()
);
```
Il componente `Presentational` dovrebbe ricevere `messages` dallo store Redux come prop.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
const props = PresentationalComponent.props();
return Array.isArray(props.messages);
})()
);
```
Il componente `Presentational` dovrebbe ricevere il creatore dell'azione `submitMessage` come prop.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
const props = PresentationalComponent.props();
return typeof props.submitNewMessage === 'function';
})()
);
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
```
## --seed-contents--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// React-Redux:
const mapStateToProps = (state) => {
return { messages: state }
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (newMessage) => {
dispatch(addMessage(newMessage))
}
}
};
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// Define the Container component here:
class AppWrapper extends React.Component {
constructor(props) {
super(props);
}
render() {
// Complete the return statement:
return (null);
}
};
```
# --solutions--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// React-Redux:
const mapStateToProps = (state) => {
return { messages: state }
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (newMessage) => {
dispatch(addMessage(newMessage))
}
}
};
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
};
```

View File

@ -0,0 +1,397 @@
---
id: 5a24c314108439a4d4036149
title: Estrai lo stato locale in Redux
challengeType: 6
forumTopicId: 301428
dashedName: extract-local-state-into-redux
---
# --description--
Hai quasi finito! Ricorda che hai scritto tutto il codice Redux in modo che Redux possa controllare la gestione dello stato della tua app di messaggi React. Ora che Redux è connesso, è necessario estrarre la gestione dello stato dal componente `Presentational` per metterla in Redux. Attualmente, hai collegato Redux, ma stai gestendo lo stato localmente all'interno del componente `Presentational`.
# --instructions--
Nel componente `Presentational`, per prima cosa, rimuovi la proprietà `messages` nello `state` locale. Questi messaggi saranno gestiti da Redux. Successivamente, modifica il metodo `submitMessage()` in modo che invii `submitNewMessage()` da `this.props`, e gli passi l'input del messaggio corrente prendendolo dallo `state` locale come argomento. Poiché hai rimosso `messages` dallo stato locale, rimuovi la proprietà `messages` dalla chiamata a `this.setState()` anche qui. Infine, modifica il metodo `render()` in modo che mappi i messaggi ricevuti da `props` piuttosto che dallo `state`.
Una volta che queste modifiche saranno state fatte, l'applicazione continuerà a funzionare ugualmente, solo che sarà Redux a gestire lo stato. Questo esempio illustra anche come un componente può avere uno `state` locale: il tuo componente traccia ancora l'input dell'utente localmente nel proprio `state`. Puoi vedere come Redux fornisce un utile framework di gestione dello stato basato su React. Hai raggiunto inizialmente lo stesso risultato usando solo lo stato locale di React, e questo è di solito possibile con applicazioni semplici. Tuttavia, mano a mano che le applicazioni diventeranno più grandi e più complesse, lo stesso farà lo stato, e questo è il problema risolto da Redux.
# --hints--
L' `AppWrapper` dovrebbe essere presentata nella pagina.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('AppWrapper').length === 1;
})()
);
```
Il componente `Presentational` dovrebbe essere presentato nella pagina.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('Presentational').length === 1;
})()
);
```
Il componente `Presentational` dovrebbe fare il render degli elementi `h2`, `input`, `button`e `ul`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
return (
PresentationalComponent.find('div').length === 1 &&
PresentationalComponent.find('h2').length === 1 &&
PresentationalComponent.find('button').length === 1 &&
PresentationalComponent.find('ul').length === 1
);
})()
);
```
Il componente `Presentational` dovrebbe ricevere `messages` dallo store Redux come prop.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
const props = PresentationalComponent.props();
return Array.isArray(props.messages);
})()
);
```
Il componente `Presentational` dovrebbe ricevere il creatore dell'azione `submitMessage` come prop.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalComponent = mockedComponent.find('Presentational');
const props = PresentationalComponent.props();
return typeof props.submitNewMessage === 'function';
})()
);
```
Lo stato del componente `Presentational` dovrebbe contenere una proprietà, `input`, che è inizializzata a una stringa vuota.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const PresentationalState = mockedComponent
.find('Presentational')
.instance().state;
return (
typeof PresentationalState.input === 'string' &&
Object.keys(PresentationalState).length === 1
);
})()
);
```
Digitando nell'elemento `input` si dovrebbe aggiornare lo stato del componente `Presentational`.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const testValue = '__MOCK__INPUT__';
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
let initialInput = mockedComponent.find('Presentational').find('input');
const changed = () => {
causeChange(mockedComponent, testValue);
return waitForIt(() => mockedComponent);
};
const updated = await changed();
const updatedInput = updated.find('Presentational').find('input');
assert(
initialInput.props().value === '' &&
updatedInput.props().value === '__MOCK__INPUT__'
);
};
```
La spedizione del `submitMessage` nel componente `Presentational` dovrebbe aggiornare lo store di Redux e cancellare l'input nello stato locale.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
let beforeProps = mockedComponent.find('Presentational').props();
const testValue = '__TEST__EVENT__INPUT__';
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const changed = () => {
causeChange(mockedComponent, testValue);
return waitForIt(() => mockedComponent);
};
const clickButton = () => {
mockedComponent.find('button').simulate('click');
return waitForIt(() => mockedComponent);
};
const afterChange = await changed();
const afterChangeInput = afterChange.find('input').props().value;
const afterClick = await clickButton();
const afterProps = mockedComponent.find('Presentational').props();
assert(
beforeProps.messages.length === 0 &&
afterChangeInput === testValue &&
afterProps.messages.pop() === testValue &&
afterClick.find('input').props().value === ''
);
};
```
Il componente `Presentational` dovrebbe presentare i `messages` dallo store di Redux.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
let beforeProps = mockedComponent.find('Presentational').props();
const testValue = '__TEST__EVENT__INPUT__';
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const changed = () => {
causeChange(mockedComponent, testValue);
return waitForIt(() => mockedComponent);
};
const clickButton = () => {
mockedComponent.find('button').simulate('click');
return waitForIt(() => mockedComponent);
};
const afterChange = await changed();
const afterChangeInput = afterChange.find('input').props().value;
const afterClick = await clickButton();
const afterProps = mockedComponent.find('Presentational').props();
assert(
beforeProps.messages.length === 0 &&
afterChangeInput === testValue &&
afterProps.messages.pop() === testValue &&
afterClick.find('input').props().value === '' &&
afterClick.find('ul').childAt(0).text() === testValue
);
};
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
```
## --seed-contents--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// Change code below this line
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => ({
input: '',
messages: state.messages.concat(state.input)
}));
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// Change code above this line
const mapStateToProps = (state) => {
return {messages: state}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
};
```
# --solutions--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message: message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
const Provider = ReactRedux.Provider;
const connect = ReactRedux.connect;
// Change code below this line
class Presentational extends React.Component {
constructor(props) {
super(props);
this.state = {
input: ''
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.props.submitNewMessage(this.state.input);
this.setState({
input: ''
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.props.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
// Change code above this line
const mapStateToProps = (state) => {
return {messages: state}
};
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: (message) => {
dispatch(addMessage(message))
}
}
};
const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);
class AppWrapper extends React.Component {
render() {
return (
<Provider store={store}>
<Container/>
</Provider>
);
}
};
```

View File

@ -0,0 +1,115 @@
---
id: 5a24c314108439a4d4036143
title: Estrarre la logica dello stato in Redux
challengeType: 6
forumTopicId: 301429
dashedName: extract-state-logic-to-redux
---
# --description--
Ora che hai finito il componente React, devi spostare la logica che esegue localmente nel suo `state` in Redux. Questo è il primo passo per collegare la semplice applicazione React a Redux. L'unica funzionalità che la tua app ha è di aggiungere nuovi messaggi dall'utente a un elenco puntato. L'esempio è semplice e serve a dimostrare come React e Redux lavorano insieme.
# --instructions--
In primo luogo, definisci un tipo di azione `ADD` e impostalo a una const `ADD`. Quindi, definisci un creatore di azioni `addMessage()` che crea l'azione per aggiungere un messaggio. Dovrai passare un `message` a questo creatore di azioni e includere il messaggio nell'`action` restituita.
Quindi crea un reducer chiamato `messageReducer()` che gestisca lo stato dei messaggi. Lo stato iniziale dovrebbe essere un array vuoto. Questo reducer dovrebbe aggiungere un messaggio all'array di messaggi tenuti nello stato o restituire lo stato attuale. Infine, crea il tuo store di Redux e passagli il reducer.
# --hints--
La costante `ADD` dovrebbe esistere e contenere un valore uguale alla stringa `ADD`
```js
assert(ADD === 'ADD');
```
Il creatore di azioni `addMessage` dovrebbe restituire un oggetto con `type` uguale a `ADD` e `message` uguale al messaggio che gli viene passato.
```js
assert(
(function () {
const addAction = addMessage('__TEST__MESSAGE__');
return addAction.type === ADD && addAction.message === '__TEST__MESSAGE__';
})()
);
```
`messageReducer` dovrebbe essere una funzione.
```js
assert(typeof messageReducer === 'function');
```
Lo store dovrebbe esistere e avere uno stato iniziale impostato su un array vuoto.
```js
assert(
(function () {
const initialState = store.getState();
return typeof store === 'object' && initialState.length === 0;
})()
);
```
Inviare `addMessage` allo store dovrebbe sempre aggiungere un nuovo messaggio all'array di messaggi tenuti nello stato.
```js
assert(
(function () {
const initialState = store.getState();
const isFrozen = DeepFreeze(initialState);
store.dispatch(addMessage('__A__TEST__MESSAGE'));
const addState = store.getState();
return isFrozen && addState[0] === '__A__TEST__MESSAGE';
})()
);
```
Il `messageReducer` dovrebbe restituire lo stato corrente se chiamato con altre azioni.
```js
assert(
(function () {
const addState = store.getState();
store.dispatch({ type: 'FAKE_ACTION' });
const testState = store.getState();
return addState === testState;
})()
);
```
# --seed--
## --seed-contents--
```jsx
// Define ADD, addMessage(), messageReducer(), and store here:
```
# --solutions--
```jsx
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
```

View File

@ -0,0 +1,102 @@
---
id: 5a24c314108439a4d4036141
title: Iniziare con React Redux
challengeType: 6
forumTopicId: 301430
dashedName: getting-started-with-react-redux
---
# --description--
Questa serie di sfide mostra come utilizzare Redux con React. In primo luogo, ecco un ripasso di alcuni dei principi fondamentali di ciascuna tecnologia. React è una libreria di visualizzazione alla quale fornisci dei dati, che poi li presenta in modo efficiente e affidabile. Redux è un framework di gestione dello stato che puoi usare per semplificare la gestione dello stato della tua applicazione. In genere, in un'applicazione React Redux, si crea un singolo store Redux che gestisce lo stato dell'intera app. I componenti React ricevono solo i dati presenti nello store che sono rilevanti per il loro ruolo. Quindi si inviano le azioni direttamente dai componenti React, che quindi attivano gli aggiornamenti dello store.
Anche se i componenti React possono gestire il proprio stato localmente, quando si dispone di un'app complessa è generalmente meglio mantenere lo stato dell'app in una singola posizione con Redux. Ci sono eccezioni quando i singoli componenti possono avere uno stato locale specifico solo per essi. Infine, dato che Redux non è progettato per essere pronto all'uso con React, è necessario utilizzare il pacchetto `react-redux`. Esso ti fornisce un modo per passare lo `state` di Redux e spedirlo (`dispatch`) ai componenti React sotto forma di `props`.
Nel corso delle prossime sfide, in primo luogo, creerai un semplice componente React che ti permetterà di inserire nuovi messaggi di testo. Questi vengono aggiunti ad un array che viene visualizzato nella vista. Questo dovrebbe essere un bel ripasso di quello che hai imparato nelle lezioni di React. Successivamente, creerai uno store Redux e delle azioni che gestiranno lo stato dell'array dei messaggi. Infine, userai `react-redux` per collegare lo store Redux con il tuo componente, estraendo lo stato locale nello store di Redux.
# --instructions--
Inizia con un componente `DisplayMessages`. Aggiungi un costruttore a questo componente e inizializzalo con uno stato che abbia due proprietà: `input`, impostato su una stringa vuota e `messages`, impostato su un array vuoto.
# --hints--
Il componente `DisplayMessages` dovrebbe presentare un elemento `div` vuoto.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
return mockedComponent.find('div').text() === '';
})()
);
```
Il costruttore `DisplayMessages` dovrebbe essere chiamato correttamente con `super`, passandogli le `props`.
```js
(getUserInput) =>
assert(
(function () {
const noWhiteSpace = __helpers.removeWhiteSpace(getUserInput('index'));
return (
noWhiteSpace.includes('constructor(props)') &&
noWhiteSpace.includes('super(props')
);
})()
);
```
Il componente `DisplayMessages` dovrebbe avere uno stato iniziale uguale a `{input: "", messages: []}`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const initialState = mockedComponent.state();
return (
typeof initialState === 'object' &&
initialState.input === '' &&
Array.isArray(initialState.messages) &&
initialState.messages.length === 0
);
})()
);
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<DisplayMessages />, document.getElementById('root'))
```
## --seed-contents--
```jsx
class DisplayMessages extends React.Component {
// Change code below this line
// Change code above this line
render() {
return <div />
}
};
```
# --solutions--
```jsx
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
}
render() {
return <div/>
}
};
```

View File

@ -0,0 +1,260 @@
---
id: 5a24c314108439a4d4036142
title: Gestire prima lo stato locale
challengeType: 6
forumTopicId: 301431
dashedName: manage-state-locally-first
---
# --description--
Qui finirai di creare il componente `DisplayMessages`.
# --instructions--
In primo luogo, nel metodo `render()`, fai in modo che sia presentato un elemento `input`, un `button` e un `ul`. Quando l'elemento `input` cambia, dovrebbe attivare un metodo `handleChange()`. Inoltre, l'elemento `input` dovrebbe presentare il valore di `input` che è nello stato del componente. L'elemento `button` dovrebbe attivare un metodo `submitMessage()` quando viene cliccato.
In secondo luogo, scrivi questi due metodi. Il metodo `handleChange()` dovrebbe aggiornare l'`input` con quello che l'utente sta digitando. Il metodo `submitMessage()` dovrebbe concatenare il messaggio corrente (memorizzato in `input`) all'array `messages` nello stato locale, e cancellare il valore dell'`input`.
Infine, usa `ul` per mappare l'array `messages` e presentarlo sullo schermo come un elenco di elementi `li`.
# --hints--
Il componente `DisplayMessages` dovrebbe inizializzare con uno stato uguale a `{ input: "", messages: [] }`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const initialState = mockedComponent.state();
return (
typeof initialState === 'object' &&
initialState.input === '' &&
initialState.messages.length === 0
);
})()
);
```
Il componente `DisplayMessages` dovrebbe rendere un `div` contenente un elemento `h2`, un elemento `button`, un elemento `ul`, e degli elementi `li` come figli.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const state = () => {
mockedComponent.setState({ messages: ['__TEST__MESSAGE'] });
return waitForIt(() => mockedComponent);
};
const updated = await state();
assert(
updated.find('div').length === 1 &&
updated.find('h2').length === 1 &&
updated.find('button').length === 1 &&
updated.find('ul').length === 1 &&
updated.find('li').length > 0
);
};
```
`.map` dovrebbe essere utilizzato nell'array `messages`.
```js
assert(code.match(/this\.state\.messages\.map/g));
```
L'elemento `input` dovrebbe presentare il valore di `input` nello stato locale.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const testValue = '__TEST__EVENT__INPUT';
const changed = () => {
causeChange(mockedComponent, testValue);
return waitForIt(() => mockedComponent);
};
const updated = await changed();
assert(updated.find('input').props().value === testValue);
};
```
Chiamare il metodo `handleChange` dovrebbe aggiornare il valore `input` nello stato in base all'input corrente.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage = '__TEST__EVENT__MESSAGE__';
const changed = () => {
causeChange(mockedComponent, testMessage);
return waitForIt(() => mockedComponent);
};
const afterInput = await changed();
assert(
initialState.input === '' &&
afterInput.state().input === '__TEST__EVENT__MESSAGE__'
);
};
```
Fare clic sul pulsante `Add message` dovrebbe chiamare il metodo `submitMessage` che dovrebbe aggiungere l'`input` corrente all'array `messages` nello stato.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage_1 = '__FIRST__MESSAGE__';
const firstChange = () => {
causeChange(mockedComponent, testMessage_1);
return waitForIt(() => mockedComponent);
};
const firstResult = await firstChange();
const firstSubmit = () => {
mockedComponent.find('button').simulate('click');
return waitForIt(() => mockedComponent);
};
const afterSubmit_1 = await firstSubmit();
const submitState_1 = afterSubmit_1.state();
const testMessage_2 = '__SECOND__MESSAGE__';
const secondChange = () => {
causeChange(mockedComponent, testMessage_2);
return waitForIt(() => mockedComponent);
};
const secondResult = await secondChange();
const secondSubmit = () => {
mockedComponent.find('button').simulate('click');
return waitForIt(() => mockedComponent);
};
const afterSubmit_2 = await secondSubmit();
const submitState_2 = afterSubmit_2.state();
assert(
initialState.messages.length === 0 &&
submitState_1.messages.length === 1 &&
submitState_2.messages.length === 2 &&
submitState_2.messages[1] === testMessage_2
);
};
```
Il metodo `submitMessage` dovrebbe cancellare l'input corrente.
```js
async () => {
const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages));
const waitForIt = (fn) =>
new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100));
const causeChange = (c, v) =>
c.find('input').simulate('change', { target: { value: v } });
const initialState = mockedComponent.state();
const testMessage = '__FIRST__MESSAGE__';
const firstChange = () => {
causeChange(mockedComponent, testMessage);
return waitForIt(() => mockedComponent);
};
const firstResult = await firstChange();
const firstState = firstResult.state();
const firstSubmit = () => {
mockedComponent.find('button').simulate('click');
return waitForIt(() => mockedComponent);
};
const afterSubmit = await firstSubmit();
const submitState = afterSubmit.state();
assert(firstState.input === testMessage && submitState.input === '');
};
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<DisplayMessages />, document.getElementById('root'))
```
## --seed-contents--
```jsx
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
}
// Add handleChange() and submitMessage() methods here
render() {
return (
<div>
<h2>Type in a new Message:</h2>
{ /* Render an input, button, and ul below this line */ }
{ /* Change code above this line */ }
</div>
);
}
};
```
# --solutions--
```jsx
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
```

View File

@ -0,0 +1,107 @@
---
id: 5a24c314108439a4d4036146
title: Mappare la spedizione delle props
challengeType: 6
forumTopicId: 301432
dashedName: map-dispatch-to-props
---
# --description--
La funzione `mapDispatchToProps()` viene utilizzata per fornire specifici creatori di azioni ai componenti React in modo che possano inviare azioni allo store di Redux. La struttura è simile alla funzione `mapStateToProps()` che hai scritto nell'ultima sfida. Essa restituisce un oggetto che mappa azioni di invio a nomi di proprietà, che diventano `props` del componente. Tuttavia, invece di restituire una parte dello `state`, ogni proprietà restituisce una funzione che chiama `dispatch` con un creatore di azione e tutti i dati rilevanti per l'azione. Hai accesso a questa `dispatch` perché è passata a `mapDispatchToProps()` come parametro quando definisci la funzione, proprio come hai passato `state` a `mapStateToProps()`. Dietro le quinte, React Redux sta usando `store.dispatch()` di Redux per eseguire queste spedizioni con `mapDispatchToProps()`. Questo è simile a come usa `store.subscribe()` per i componenti che sono mappati allo `state`.
Ad esempio, hai un creatore di azione `loginUser()` che richiede uno `username` come payload dell'azione. L'oggetto restituito da `mapDispatchToProps()` per questo creatore di azione sarà di questo tipo:
```jsx
{
submitLoginUser: function(username) {
dispatch(loginUser(username));
}
}
```
# --instructions--
L'editor di codice fornisce un creatore di azioni chiamato `addMessage()`. Scrivi la funzione `mapDispatchToProps()` che richiede `dispatch` come argomento, quindi restituisce un oggetto. L'oggetto dovrebbe avere una proprietà `submitNewMessage` impostata alla funzione dispatch, che prende un parametro per il nuovo messaggio quando effettua il dispatch di `addMessage()`.
# --hints--
`addMessage` dovrebbe restituire un oggetto con chiavi `type` e `message`.
```js
assert(
(function () {
const addMessageTest = addMessage();
return (
addMessageTest.hasOwnProperty('type') &&
addMessageTest.hasOwnProperty('message')
);
})()
);
```
`mapDispatchToProps` dovrebbe essere una funzione.
```js
assert(typeof mapDispatchToProps === 'function');
```
`mapDispatchToProps` dovrebbe restituire un oggetto.
```js
assert(typeof mapDispatchToProps() === 'object');
```
Spedire `addMessage` con `submitNewMessage` da `mapDispatchToProps` dovrebbe restituire un messaggio alla funzione dispatch.
```js
assert(
(function () {
let testAction;
const dispatch = (fn) => {
testAction = fn;
};
let dispatchFn = mapDispatchToProps(dispatch);
dispatchFn.submitNewMessage('__TEST__MESSAGE__');
return (
testAction.type === 'ADD' && testAction.message === '__TEST__MESSAGE__'
);
})()
);
```
# --seed--
## --seed-contents--
```jsx
const addMessage = (message) => {
return {
type: 'ADD',
message: message
}
};
// Change code below this line
```
# --solutions--
```jsx
const addMessage = (message) => {
return {
type: 'ADD',
message: message
}
};
// Change code below this line
const mapDispatchToProps = (dispatch) => {
return {
submitNewMessage: function(message) {
dispatch(addMessage(message));
}
}
};
```

View File

@ -0,0 +1,69 @@
---
id: 5a24c314108439a4d4036145
title: Mappare lo stato sulle props
challengeType: 6
forumTopicId: 301433
dashedName: map-state-to-props
---
# --description--
Il componente `Provider` consente di fornire `state` e `dispatch` ai componenti React, ma devi specificare esattamente quale stato e azioni desideri. In questo modo, ti assicuri che ogni componente abbia accesso solo allo stato di cui ha bisogno. Lo si ottiene creando due funzioni: `mapStateToProps()` e `mapDispatchToProps()`.
In queste funzioni, dichiari a quali parti dello stato vuoi avere accesso e quali creatori di azione devi essere in grado di inviare. Una volta che queste funzioni saranno pronte, vedrai come utilizzare il metodo React Redux `connect` per collegarli ai tuoi componenti in un'altra sfida.
**Nota:** Dietro le quinte, React Redux utilizza il metodo `store.subscribe()` per implementare `mapStateToProps()`.
# --instructions--
Crea una funzione `mapStateToProps()`. Questa funzione dovrebbe prendere `state` come argomento, quindi restituire un oggetto che mappa quello stato a specifici nomi di proprietà. Queste proprietà diventeranno accessibili al tuo componente tramite `props`. Dal momento che questo esempio mantiene l'intero stato dell'app in un unico array, è possibile passare l'intero stato al tuo componente. Crea una proprietà `messages` nell'oggetto che viene restituito e impostala a `state`.
# --hints--
La costante `state` dovrebbe essere un array vuoto.
```js
assert(Array.isArray(state) && state.length === 0);
```
`mapStateToProps` dovrebbe essere una funzione.
```js
assert(typeof mapStateToProps === 'function');
```
`mapStateToProps` dovrebbe restituire un oggetto.
```js
assert(typeof mapStateToProps() === 'object');
```
Passare un array come stato a `mapStateToProps` dovrebbe restituire questo array associato a una chiave `messages`.
```js
assert(mapStateToProps(['messages']).messages.pop() === 'messages');
```
# --seed--
## --seed-contents--
```jsx
const state = [];
// Change code below this line
```
# --solutions--
```jsx
const state = [];
// Change code below this line
const mapStateToProps = (state) => {
return {
messages: state
}
};
```

View File

@ -0,0 +1,69 @@
---
id: 5a24c314108439a4d403614a
title: Andare oltre
challengeType: 6
forumTopicId: 301434
dashedName: moving-forward-from-here
---
# --description--
Congratulazioni! Hai finito le lezioni su React e Redux. C'è un ultima cosa che vale la pena di sottolineare prima di andare avanti. In genere, non scriverai le applicazioni React in un editor di codice come questo. Questa sfida ti dà uno sguardo su come appare la sintassi se stai lavorando con npm e un file system sulla tua macchina. Il codice dovrebbe apparire simile, tranne per l'uso delle istruzioni `import` (queste importano tutte le dipendenze che ti sono sono state fornite nelle sfide). La sezione "Gestire i pacchetti con npm" copre npm in maggiore dettaglio.
Infine, scrivere codice React e Redux richiede generalmente una certa configurazione. Questo può diventare rapidamente complicato. Se sei interessato a sperimentare sulla tua macchina, la <a href="https://github.com/facebookincubator/create-react-app" target="_blank" rel="nofollow">Create React App</a> viene configurata ed è pronta all'uso.
In alternativa, puoi abilitare Babel come Preprocessore JavaScript in CodePen, aggiungere React e ReactDOM come risorse JavaScript esterne e lavorare anche lì.
# --instructions--
Scrivi il messaggio `'Now I know React and Redux!'` nella console.
# --hints--
Il messaggio `Now I know React and Redux!` dovrebbe essere scritto nella console.
```js
(getUserInput) =>
assert(
/console\s*\.\s*log\s*\(\s*('|"|`)Now I know React and Redux!\1\s*\)/.test(
getUserInput('index')
)
);
```
# --seed--
## --seed-contents--
```jsx
/*
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider, connect } from 'react-redux'
import { createStore, combineReducers, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import rootReducer from './redux/reducers'
import App from './components/App'
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
ReactDOM.render(
<Provider store={store}>
<App/>
</Provider>,
document.getElementById('root')
);
*/
// Only change code below this line
```
# --solutions--
```jsx
console.log('Now I know React and Redux!');
```

View File

@ -0,0 +1,263 @@
---
id: 5a24c314108439a4d4036144
title: Usare il Provider per connettere Redux a React
challengeType: 6
forumTopicId: 301435
dashedName: use-provider-to-connect-redux-to-react
---
# --description--
Nell'ultima sfida, hai creato uno store Redux per gestire l'array dei messaggi e hai creato un'azione per aggiungere nuovi messaggi. Il passo successivo è quello di fornire a React l'accesso allo store di Redux e le azioni di cui ha bisogno per inviare aggiornamenti. React Redux fornisce il suo pacchetto `react-redux` per aiutare a realizzare questi compiti.
React Redux fornisce una piccola API con due caratteristiche chiave: `Provider` e `connect`. Un'altra sfida riguarda `connect`. Il `Provider` è un componente wrapper di React Redux che racchiude la tua app React. Questo wrapper consente quindi di accedere alle funzioni dello `store` di Redux e al metodo `dispatch` da tutto il tuo albero dei componenti. `Provider` richiede due proprietà, lo store di Redux e i componenti figli della tua app. La definizione del `Provider` per un componente dell'App potrebbe assomigliare a questa:
```jsx
<Provider store={store}>
<App/>
</Provider>
```
# --instructions--
L'editor di codice ora mostra tutto il tuo codice Redux e React dalle sfide precedenti. Include lo store di Redux, le azioni e il componente `DisplayMessages`. L'unico elemento nuovo è il componente `AppWrapper` in basso. Utilizza questo componente di primo livello per presentare il `Provider` da `ReactRedux`, e passare lo store di Redux come proprietà. Quindi presenta il componente `DisplayMessages` come figlio. Una volta che hai finito, dovresti vedere il tuo componente React presentato nella pagina.
**Nota:** React Redux è disponibile come variabile globale qui, in modo da poter accedere al Provider con la notazione a punti. Il codice nell'editor sfrutta questa caratteristica e lo imposta a una costante `Provider` da utilizzare nel metodo render di `AppWrapper`.
# --hints--
Dovrebbe essere avviato il rendering di `AppWrapper`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return mockedComponent.find('AppWrapper').length === 1;
})()
);
```
Il componente wrapper `Provider` dovrebbe avere una prop `store` passata ad esso, uguale allo store di Redux.
```js
(getUserInput) =>
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return __helpers
.removeWhiteSpace(getUserInput('index'))
.includes('<Providerstore={store}>');
})()
);
```
`DisplayMessages` dovrebbe essere presentato come figlio di `AppWrapper`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return (
mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1
);
})()
);
```
Il componente `DisplayMessages` dovrebbe presentare gli elementi `h2`, `input`, `button`e `ul`.
```js
assert(
(function () {
const mockedComponent = Enzyme.mount(React.createElement(AppWrapper));
return (
mockedComponent.find('div').length === 1 &&
mockedComponent.find('h2').length === 1 &&
mockedComponent.find('button').length === 1 &&
mockedComponent.find('ul').length === 1
);
})()
);
```
# --seed--
## --after-user-code--
```jsx
ReactDOM.render(<AppWrapper />, document.getElementById('root'))
```
## --seed-contents--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
const Provider = ReactRedux.Provider;
class AppWrapper extends React.Component {
// Render the Provider below this line
// Change code above this line
};
```
# --solutions--
```jsx
// Redux:
const ADD = 'ADD';
const addMessage = (message) => {
return {
type: ADD,
message
}
};
const messageReducer = (state = [], action) => {
switch (action.type) {
case ADD:
return [
...state,
action.message
];
default:
return state;
}
};
const store = Redux.createStore(messageReducer);
// React:
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
input: '',
messages: []
}
this.handleChange = this.handleChange.bind(this);
this.submitMessage = this.submitMessage.bind(this);
}
handleChange(event) {
this.setState({
input: event.target.value
});
}
submitMessage() {
this.setState((state) => {
const currentMessage = state.input;
return {
input: '',
messages: state.messages.concat(currentMessage)
};
});
}
render() {
return (
<div>
<h2>Type in a new Message:</h2>
<input
value={this.state.input}
onChange={this.handleChange}/><br/>
<button onClick={this.submitMessage}>Submit</button>
<ul>
{this.state.messages.map( (message, idx) => {
return (
<li key={idx}>{message}</li>
)
})
}
</ul>
</div>
);
}
};
const Provider = ReactRedux.Provider;
class AppWrapper extends React.Component {
// Change code below this line
render() {
return (
<Provider store = {store}>
<DisplayMessages/>
</Provider>
);
}
// Change code above this line
};
```