chore(i18n,curriculum): processed translations - new ukrainian (#44447)

This commit is contained in:
camperbot
2021-12-10 11:14:24 +05:30
committed by GitHub
parent 8651ee1797
commit 0473dedf47
1663 changed files with 156692 additions and 1 deletions

View File

@@ -0,0 +1,175 @@
---
id: 5a24c314108439a4d4036154
title: Об'єднати множинні зменшувачі
challengeType: 6
forumTopicId: 301436
dashedName: combine-multiple-reducers
---
# --description--
Коли стан вашого додатку стає більш складним, спокусливіше було б розділити стан на кілька частин. Замість цього запам'ятайте перший принцип Redux: весь стан програми відбувається в одному об'єкті стану, в сховищі. Тому, Redux забезпечує зменшення поєднання як рішення складного стану моделі. Ви визначаєте декілька знижень, щоб працювати з різними частинами вашого стану програм, і потім складаєте ці зменшувачі разом в одному кореневому варіанті. Кореневий варіант передається в Rudex за допомогою `createStore()` методу.
Для того, щоб дозволити нам комбінувати декілька скорочень разом, Redux надає `combineReducers()` метод. Цей метод приймає об'єкт як аргумент, в якому ви зазначаєте властивості, які пов'язують ключі з конкретними зменшувальними функціями. Назва, яку ви даєте ключам, буде використовуватися Redux як назва для відповідного фрагменту стану.
Як правило, для кожної частини програми корисно створити скорочення якщо вони різні або унікальні. Наприклад, у сповіщенні за допомогою автентифікації користувачів, один лічильник може обробляти автентифікацію, поки інший обробляє текст і замітки, які користувач надсилає. Для такої програми ми могли б написати метод `combineReducers()` на зразок цього:
```js
const rootReducer = Redux.combineReducers({
auth: authenticationReducer,
notes: notesReducer
});
```
Тепер для доступу `notes` буде встановлено весь режим, пов'язаний з нашими нотатками та оброблено нашими `notesReducer`. Ось так можна скласти кілька скорочень для керування більш складним станом програми. У цьому прикладі, стан, утриманий у сховищі Redux, буде єдиним об'єктом, що містить `auth` і `notes` властивостей.
# --instructions--
Існує `counterReducer()` і `authReducer()` функції, які надані в текстовому редакторі, а також Redux сховищі. Завершіть запис функції `rootReducer()` за допомогою методу `Redux.combineReducers()`. Призначте `counterReducer` під назвою `count` і `authReducer` до ключа під назвою `auth`.
# --hints--
Код `counterReducer` повинен збільшити а `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` повинен переключити `state` `authenticated` між `true` і `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;
})()
);
```
У сховищі `state` має бути два ключі: `count` який містить номер і `auth`, який містить об'єкт. `auth` повинен мати властивість `authenticated`, який містить логічне значення.
```js
assert(
(function () {
const state = store.getState();
return (
typeof state.auth === 'object' &&
typeof state.auth.authenticated === 'boolean' &&
typeof state.count === 'number'
);
})()
);
```
`rootReducer` повинен бути функцією, що поєднує `counterReducer` і `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: Копіювання об'єкта за допомогою функції Object.assign
challengeType: 6
forumTopicId: 301437
dashedName: copy-an-object-with-object-assign
---
# --description--
Останні кілька завдань стосувалися роботи з масивами, проте є способи допомогти забезпечити незмінність стану, коли стан є також `object`. Корисним інструментом для роботи з об'єктами є функція `Object.assign()`. Функція `Object.assign()` бере цільовий об'єкт та вихідні об'єкти та призначає властивості вихідних об'єктів цільовим. Будь-які властивості, що збігаються, перезаписуються властивостями у вихідних об’єктах. Це поводження об'єкта зазвичай використовується задля створення поверхневих копій об'єктів, що здійснюється за допомогою передачі порожніх об'єктів у ролі першого аргумента, за яким слідує об'єкт(-и), які ви хочете зкопіювати. Наприклад:
```js
const newObject = Object.assign({}, obj1, obj2);
```
Це створює `newObject` як новий `object`, що містить властивості, які вже існують у `obj1` та `obj2`.
# --instructions--
Стан та дії Redux були змінені для обробки `object` для `state`. Відредагуйте код для повернення нового `state` об'єкта для дій з типом `ONLINE`, який встановлює властивість `status` рядку `online`. Спробуйте використати `Object.assign()` для завершення завдання.
# --hints--
Сховище Redux має існувати та запускатися зі станом, еквівалентним об'єкту `defaultState`, заявленому у рядку 1.
```js
assert(
(function () {
const expectedState = {
user: 'CamperBot',
status: 'offline',
friends: '732,982',
community: 'freeCodeCamp'
};
const initialState = store.getState();
return DeepEqual(expectedState, initialState);
})()
);
```
`wakeUp` та `immutableReducer` - обидві мають бути функціями.
```js
assert(typeof wakeUp === 'function' && typeof immutableReducer === 'function');
```
Розміщення дії типу `ONLINE` має оновлювати властивості `status` у стані до `online`, проте НЕ може змінювати стан.
```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` слід використовувати для повернення нового стану.
```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: Створення сховища Redux
challengeType: 6
forumTopicId: 301439
dashedName: create-a-redux-store
---
# --description--
Redux - це фреймворк керування станами, який може використовуватися з низкою різних веб-технологій, включно із React.
У Redux є єдиний об'єкт стану, який відповідає за стан усього вашого застосунку. Це означає, що якщо б у вас був застосунок на React з десятьма компонентами, і кожен компонент мав би власний внутрішній стан, то увесь стан вашого застосунку визначався б по єдиному об'єкту стану, розміщеному на Redux `store` (сховищі). Це і є перший важливий принцип, який слід зрозуміти під час вивчення Redux: сховище Redux - це єдине джерело достовірних даних, коли йдеться про стан застосунку.
Це також означає, що, якщо у будь-який час, будь-яка частина вашого застосунку забажає оновити стан, то вона **має** зробити це через сховище Redux. Односпрямований потік даних дозволяє значно легше відстежувати управління станом у вашому застосунку.
# --instructions--
Redux `store` (сховище) - це об'єкт, який містить та скеровує `state` (стан) застосунку. Цей метод має назву `createStore()` на об'єкті Redux, який ви використовуєте, щоб створити `store` (сховище) Redux. Цей метод використовує функцію `reducer` як необхідний аргумент. Функція `reducer` розкривається в наступних завданнях та вже визначена для вас в редакторі коду. Вона просто бере `state` як аргумент та повертає `state`.
Вкажіть `store` змінною та призначте її методу `createStore()`, передавши у `reducer` як аргумент.
**Примітка:** код в редакторі за замовчуванням використовує синтаксис аргументів ES6 для ініціалізаціїї цього стану для утримання значення `5`. Якщо ви не знайомі з аргументами за замовчуванням, ви можете дізнатися більше у [секції ES6 в Навчальному плані ](https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/set-default-parameters-for-your-functions), що охоплює цю тему.
# --hints--
Повинно існувати сховище Redux.
```js
assert(typeof store.getState === 'function');
```
Сховище Redux повинно мати значення 5 для стану.
```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: Визначення дії Redux
challengeType: 6
forumTopicId: 301440
dashedName: define-a-redux-action
---
# --description--
Оскільки Redux це фреймворк керування станами, оновлення стану є одним з його основних завдань. В Redux, всі оновлення стану запускаються при відправленні дій. Дія це просто JavaScript об'єкт, який містить інформацію про дію, що відбулася. Redux сховище отримує ці об'єкти дій, а потім оновлює стан відповідно. Інколи дія Redux також містить певні дані. Наприклад, дія може містити ім'я користувача після його входу. У той час як дані необов'язкові, дії можуть містити властивість `type`, яка визначає 'тип' дії, що відбулася.
Вважайте дії Redux як месенджери, які доставляють інформацію про події, що відбуваються у вашому додатку до сховища Redux. Після чого сховище здійснює оновлення стану на основі дії, що відбулася.
# --instructions--
Написання дії Redux є таким же простим, як і декларація об'єкта за допомогою типової властивості. Вкажіть об'єкт `action` і надайте йому властивість `type` встановіть рядок `'LOGIN'`.
# --hints--
Об'єкт `action` повинен існувати.
```js
assert(
(function () {
return typeof action === 'object';
})()
);
```
Об'єкт `action` повинен мати властивість ключа `type` зі значенням `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: Визначення виконавця дії
challengeType: 6
forumTopicId: 301441
dashedName: define-an-action-creator
---
# --description--
Після створення дії, наступний крок це відправлення дії до Redux сховища, так щоб він зміг оновити свій стан. В Redux, ви визначаєте виконавців дій. Виконавець дії - це просто функція JavaScript, яка повертає дію. Іншими словами, виконавці дій створюють об'єкти які відображають події дій.
# --instructions--
Визначте функцію з назвою `actionCreator()`, яка повертає об'єкт `action` під час її виклику.
# --hints--
Функція `actionCreator` повинна існувати.
```js
assert(typeof actionCreator === 'function');
```
Запуск функції `actionCreator` повинен повернути об'єкт `action`.
```js
assert(typeof action === 'object');
```
Повернений об'єкт `action` повинен мати властивість ключа `type` зі значенням `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: Відправлення події дії
challengeType: 6
forumTopicId: 301442
dashedName: dispatch-an-action-event
---
# --description--
Метод `dispatch` це те, що ви використовуєте для відправлення дій до сховища Redux. Виклик `store.dispatch()` і передача значення, повернутого від виконавця дії, відправляє дію назад у сховище.
Згадайте що виконавці дій повертають об'єкт з властивістю типу, яка вказує дію, що відбулася. Тоді метод відправляє об'єкт дії до сховища Redux. На підставі прикладу з попереднього завдання, наступні рядки є еквівалентними, і обидва відправляють дію типу `LOGIN`:
```js
store.dispatch(actionCreator());
store.dispatch({ type: 'LOGIN' });
```
# --instructions--
Сховище Redux у редакторі коду має ініціалізований стан, де об'єкт містить властивість `login`, яка в даний момент встановлена на `false`. Існує також виконавець дії з назвою `loginAction()`, що повертає дію типу `LOGIN`. Відправте дію `LOGIN` до сховища Redux шляхом виклику методу `dispatch`, і передайте в дію створену `loginAction()`.
# --hints--
Виклик функції `loginAction` повинен повернути об'єкт з набором параметрів `type` до рядку `LOGIN`.
```js
assert(loginAction().type === 'LOGIN');
```
Сховище має бути ініціалізованим з об'єктом, що має параметр `login` встановлений на `false`.
```js
assert(store.getState().login === false);
```
Метод `store.dispatch()` використовується для відправлення дії типу `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: Отримання стану з сховища Redux
challengeType: 6
forumTopicId: 301443
dashedName: get-state-from-the-redux-store
---
# --description--
Об'єкт сховища Redux надає кілька методів які дозволяють вам взаємодіяти з ним. Наприклад, ви можете отримати поточне значення `state` в об'єкті сховища Redux за допомогою методу `getState()`.
# --instructions--
Код з попереднього завдання переписаний більш лаконічно у редакторі коду. Використайте `store.getState()` щоб отримати `state` з `store`, і призначте до нової змінної `currentState`.
# --hints--
Сховище Redux повинно мати значення 5 для початкового стану.
```js
assert(store.getState() === 5);
```
Змінна `currentState` повинна існувати і повинна встановлювати поточний стан сховища 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: Обробка дії в сховищі
challengeType: 6
forumTopicId: 301444
dashedName: handle-an-action-in-the-store
---
# --description--
Після того, як дія була створена та відправлена, сховище Redux мусить знати, як відповідати на цю дію. Це — завдання для функції `reducer`. Зменшувачі в Redux відповідають за стан змін, які відбуваються у відповідь на дії. `reducer` використовує `state` та `action` як аргументи, і це завжди повертає новий `state`. Важливим є те, що це — **єдина** роль зменшувача. У нього немає побічних дій — він не викличе кінцеву точку API й не має підводних каменів. Зменшувач — це просто чиста функція, яка використовує стан і дію та повертає новий стан.
Іншим ключовим принципом Redux є те, що `state` — тільки для читання. Іншими словами, функція `reducer` мусить **завжди** повертати нову копію `state` і ніколи не змінювати безпосередньо стан. Redux не забезпечує незмінність стану, щоправда, ви відповідаєте за його забезпечення у вашому коді та функціях зменшувача. Ви зможете попрактикуватись у цьому в наступних завданнях.
# --instructions--
Редактор коду має попередній приклад, точно так само, як і початок функції `reducer` для вас. Заповніть основну частину функції `reducer` так, щоб, якщо вона отримає дію типу `'LOGIN'`, то поверне об'єкт з набором `login` для `true`. В іншому випадку, вона поверне поточний `state`. Зверніть увагу, що поточний `state` та відправлена `action` підходять для зменшувача, то ж ви зможете отримати доступ безпосередньо до типу дії з `action.type`.
# --hints--
Виклик функції `loginAction` повинен повертатися як об'єкт з типом набору параметрів для рядка `LOGIN`.
```js
assert(loginAction().type === 'LOGIN');
```
Сховище мусить бути ініціалізованим з об'єктом, що має параметр `login`, встановлений на `false`.
```js
assert(store.getState().login === false);
```
Відправлення `loginAction` мусить оновити параметр `login` у сховищі, до стану `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginAction());
const afterState = store.getState();
return initialState.login === false && afterState.login === true;
})()
);
```
Якщо дія не є типом `LOGIN`, то сховище мусить повернути поточний стан.
```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: Незмінний стан
challengeType: 6
forumTopicId: 301445
dashedName: never-mutate-state
---
# --description--
Ці останні завдання описують кілька методів забезпечення ключового принципу незмінності стану в Redux. Незмінний стан означає, що ви ніколи безпосередньо не змінюєте стан, натомість ви повертаєте нову копію стану.
Якби ви сфотографували стан додатку Redux через деякий час, ви б побачите щось на зразок `state 1`, `state 2`, `state 3`, `state 4`, `...` і так далі, де кожен стан може бути подібним до останнього, але кожен - це окрема частина даних. Ця незмінність, насправді, є тим, що створює такі функції як налагодження подорожі у часі, про яку ви, можливо, чули.
Redux не активно застосовує незмінність стану у своєму сховищі чи редукторах, ця відповідальність лягає на програміста. На щастя, JavaScript (особливо ES6) надає кілька корисних інструментів, які ви можете використати для забезпечення незмінності вашого стану, чи це `string`, `number`, `array`, чи `object`. Зверніть увагу, що рядки і цифри є простими значеннями і є незмінними за своїми властивостями. Іншими словами, 3 завжди є 3. Ми не можемо змінити значення числа 3. Однак `array` або `object`, є незмінними. На практиці, ваш стан, ймовірно, складатиметься з `array` або `object`, оскільки це корисні структури даних для представлення багатьох типів інформації.
# --instructions--
В редакторі коду є `store` і `reducer` для керування елементами списку справ. Завершіть написання випадку `ADD_TO_DO` в редукторі, щоб додати новий список справ у стан. Існує кілька способів досягти цього з стандартним JavaScript або ES6. Подивіться, чи ви зможете знайти спосіб повернути новий масив з елементом `action.todo`, доданим до кінця.
# --hints--
Сховище Redux повинне існувати й ініціалізуватися зі станом, який дорівнює масиву `todos` в редакторі коду.
```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` і `immutableReducer` мають бути функціями.
```js
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
```
Коли у Redux сховище відправляєте дію типу `ADD_TO_DO`, ви повинні додати `todo` і не можете змінювати стан.
```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: Реєстрація слухача Сховища
challengeType: 6
forumTopicId: 301446
dashedName: register-a-store-listener
---
# --description--
Інший метод, до якого ви маєте доступ на сховищі Redux `store` це `store.subscribe()`. Він дозволяє прив'язати функції слухача до сховища, які викликаються коли дія відбувається у сховищі. Одне просте використання цього методу це прив'язка функції до сховища, що просто записує повідомлення кожен раз, коли дія отримується і сховище оновлюється.
# --instructions--
Напишіть функцію зворотного зв'язку, яка збільшує глобальну змінну `count` кожен раз коли сховище отримує дію, і передайте цю функцію в методі `store.subscribe()`. Ви побачите, що `store.dispatch()` викликається три рази підряд, кожен раз безпосереднього проходячи в об'єкт дії. Спостерігайте вихідні дані консолі під час відправлення дії, щоб побачити оновлення які відбуваються.
# --hints--
Відправлення дії `ADD` до сховище має збільшити стан на `1`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch({ type: 'ADD' });
const newState = store.getState();
return newState === initialState + 1;
})()
);
```
Використовуючи `store.subscribe` має бути функція слухача прив'язна до сховища.
```js
(getUserInput) => assert(getUserInput('index').match(/store\s*\.\s*subscribe\(/gm));
```
Дія `store.subscribe` має отримувати функцію.
```js
(getUserInput) => assert(getUserInput('index').match(/(\s*function\s*)|(\s*\(\s*\)\s*=>)/gm))
```
Зворотний виклик до `store.subscribe` повинен також збільшити глобальну змінну `count`, оскільки сховище оновлюється.
```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: Вилучення елементу з масиву
challengeType: 6
forumTopicId: 301447
dashedName: remove-an-item-from-an-array
---
# --description--
Час потренуватися вилучати елементи з масиву. Поширені оператори також можуть тут використовуватись. Інші корисні методи JavaScript включають `slice()` та `concat()`.
# --instructions--
Зменшувач та виконавець дії були змінені на те, щоб вилучати елемент з масиву, ґрунтуючись на індексі елемента. Завершіть написання зменшувача, щоб новий стан масиву повернувся з елементом за конкретним видаленим індексом.
# --hints--
Сховище Redux має існувати та ініціалізуватися зі станом, що дорівнює `[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` та `immutableReducer` мають бути функціями.
```js
assert(
typeof removeItem === 'function' && typeof immutableReducer === 'function'
);
```
Виконання дії `removeItem` має видаляти елементи зі стану та НЕ змінювати його.
```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: Надсилання даних про дії до сховища
challengeType: 6
forumTopicId: 301448
dashedName: send-action-data-to-the-store
---
# --description--
Ви вже дізнались як виконувати дії зі сховищем Redux, але досі ці дії не містили ніякої інформації, крім `type`. Ви також можете надсилати певні дані разом з вашими діями. Насправді це дуже поширене явище, тому що дії зазвичай виникають з певних взаємодій, і вони, як правило, мають у собі деякі дані. Сховище Redux зазвичай має знати про ці дані.
# --instructions--
Є основний виконавець дій `notesReducer()` та `addNoteText()`, визначені в редакторі коду. Завершіть основну частину функції `addNoteText()`, щоб вона повернула об'єкт `action`. Об'єкт має включати властивість `type` зі значенням `ADD_NOTE`, а також набір властивостей `text` для даних `note`, які призначені для виконавця дій. При виклику виконавця дій, ви передаєте особливу інформацію, що маєте доступ до об'єкта.
Далі, завершіть написання команди `switch` у `notesReducer()`. Ви маєте додати випадок, який опрацьовує дії `addNoteText()`. Цей випадок має спрацьовувати щоразу, коли є дія типу `ADD_NOTE` і вона повинен повертатися як властивість `text` у вхідній `action` як новий `state`.
Ця дія виконується у нижній частині коду. Щойно закінчите, запустіть код і зверніть увагу на консоль. Це все, що потрібно, щоб надіслати особливі дані про дії у сховище та використовувати під час оновлення сховища `state`.
# --hints--
Виконавець дій `addNoteText` повинен повертатися як об'єкт з ключами `type` та `text`.
```js
assert(
(function () {
const addNoteFn = addNoteText('__TEST__NOTE');
return addNoteFn.type === ADD_NOTE && addNoteFn.text === '__TEST__NOTE';
})()
);
```
Запуск дії типу `ADD_NOTE` з виконавцем дії `addNoteText` має оновлювати `state` до рядка, переданого виконавцю дій.
```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: Використовуйте команду Switch для виконання декількох дій
challengeType: 6
forumTopicId: 301449
dashedName: use-a-switch-statement-to-handle-multiple-actions
---
# --description--
Ви можете вказати в сховищі Redux, як обробляти кілька типів дій. Припустимо, ви керуєте автентифікацією користувача у вашому сховищі Redux. Ви хочете мати чітке уявлення, коли користувачі входять у систему та коли вони виходять. Ви передаєте це єдиним чітким об’єктом із властивістю `authenticated`. Вам також потрібні творці дій, які створюють дії, що відповідають призначеним для входу користувача та виходу користувача, разом з самими об'єктами.
# --instructions--
У редакторі коду є сховище, дії та виконавці створені для вас. Заповніть функцію `reducer` для обробки кількох дій автентифікації. Використовуйте команду JavaScript `switch` у `reducer`, щоб відповідати на різні події дій. Це стандартний шаблон для написання Redux reducers. Команда switch повинна перемикати `action.type` і повертати відповідний стан автентифікації.
**Note:**Наразі не турбуйтеся про незмінність стану, оскільки в цьому прикладі він невеликий і простий. Для кожної дії, можна повернути новий об'єкт - наприклад, `{authenticated: true}`. Також не забудьте написати `default` випадок у вашій команді switch, яка повертає поточний`state`. Це важливо, оскільки, коли у вашому додатку є кілька reducers, усі вони запускаються щоразу, коли надсилається дія, навіть якщо ця дія не пов’язана з цим reducer. У такому випадку варто переконатися, що ви повертаєте поточний `state`.
# --hints--
Виклик функції `loginUser` має повернути об’єкт із властивістю типу рядок `LOGIN`.
```js
assert(loginUser().type === 'LOGIN');
```
Виклик функції `logoutUser` має повернути об’єкт із властивістю типу рядок `LOGOUT`.
```js
assert(logoutUser().type === 'LOGOUT');
```
Зберігання має бути ініціалізовано об'єктом із властивістю `authenticated`, встановленою на `false`.
```js
assert(store.getState().authenticated === false);
```
Відправлення `loginUser` має оновити властивість `authenticated` у стані сховища до `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginUser());
const afterLogin = store.getState();
return (
initialState.authenticated === false && afterLogin.authenticated === true
);
})()
);
```
Відправлення `logoutUser` має оновити властивість `authenticated` у стані сховища до `false`.
```js
assert(
(function () {
store.dispatch(loginUser());
const loggedIn = store.getState();
store.dispatch(logoutUser());
const afterLogout = store.getState();
return (
loggedIn.authenticated === true && afterLogout.authenticated === false
);
})()
);
```
Функція `authReducer` повинна обробляти кілька типів дій за допомогою команди `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: Використання const для типів дій
challengeType: 6
forumTopicId: 301450
dashedName: use-const-for-action-types
---
# --description--
Поширена практика при роботі з Redux призначати типи дій як константи тільки для читання, а потім посилатися на ці константи в місцях, де вони використовуються. Ви можете повернути код, з яким ви працюєте, щоб записати типи дій як `const` декларації.
# --instructions--
Оголосіть `LOGIN` і `LOGOUT` як значення `const` і призначте їх рядкам `'LOGIN'` і `'LOGOUT'` відповідно. Потім відредагуйте `authReducer()` та генераторів дії на посилання на ці константи замість значень у рядку.
**Примітка:** Зазвичай константи пишуться великими літерами, це стандартна практика у Redux.
# --hints--
Виклик функції `loginUser` повинен повернути об'єкт з набором параметрів `type` до рядку `LOGIN`.
```js
assert(loginUser().type === 'LOGIN');
```
Виклик функції `loginUser` повинен повернути об'єкт з набором параметрів `type` до рядку `LOGOUT`.
```js
assert(logoutUser().type === 'LOGOUT');
```
Сховище має бути ініціалізованим з об'єктом, що має параметр `login`, встановлений на `false`.
```js
assert(store.getState().authenticated === false);
```
Викликання `loginUser` мусить оновити параметр `login` у сховищі на `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(loginUser());
const afterLogin = store.getState();
return (
initialState.authenticated === false && afterLogin.authenticated === true
);
})()
);
```
Викликання `logoutUser` мусить оновити параметр `login` у сховищі на `false`.
```js
assert(
(function () {
store.dispatch(loginUser());
const loggedIn = store.getState();
store.dispatch(logoutUser());
const afterLogout = store.getState();
return (
loggedIn.authenticated === true && afterLogout.authenticated === false
);
})()
);
```
Функція `authReducer` повинна обробляти кілька типів дій за допомогою 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` та `LOGOUT` повинні бути оголошені як `const` значення і повинні бути призначені рядки `LOGIN` та `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)
);
```
Генератори дій та редюсер мають посилатися на `LOGIN` та `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: Використання Middleware для опрацювання асинхронних дій
challengeType: 6
forumTopicId: 301451
dashedName: use-middleware-to-handle-asynchronous-actions
---
# --description--
До цього моменту в завданнях ми уникали обговорення асинхронних дій, хоча вони є обов'язковою частиною веб-розробки. У певний момент вам прийдеться викликати асинхронні кінцеві точки у вашому додатку Redux. Отже, як опрацьовувати ці всі типи запитів? Задля цього Redux було спеціально розроблено проміжне програмне забезпечення Redux Thunk. Нижче наведено як використовувати цей додаток з Redux.
Для використання проміжного програмного забезпечення Redux Thunk, передайте його як аргумент до `Redux.applyMiddleware()`. Ця команда передається далі, як другий вибірковий параметр для функції `createStore()`. Щоб побачити це, подивіться на код, розміщений внизу редактора. Таким чином для створення асинхронної дії ви повертаєте функцію в генераторі дії, яка отримує `dispatch`, як аргумент. У межах цієї функції ви можете відправляти дії та виконувати асинхронні запити.
У цьому прикладі асинхронний запит моделюється за допомогою команди `setTimeout()`. Загальноприйнято надсилати дію перед початком будь-якої асинхронної поведінки, щоб стан вашої програми знав про те, що запитуються деякі дані (наприклад, у цьому стані може показуватися значок завантаження). Як тільки ви отримуєте дані, ви відправляєте іншу дію, яка переносить дані, як інформаційне наповнення разом з інформацією про завершену дію.
Пам'ятайте, що ви передаєте `dispatch`, як параметр для цього спеціального генератора дії. Це те, що ви будете використовувати для відправлення ваших дій. Ви просто передасте дію безпосередньо для відправлення, а проміжне програмне забезпечення потурбується про все інше.
# --instructions--
Пропишіть обидві команди відправлення у створювачі дії `handleAsync()`. Відправте `requestingData()` перед `setTimeout()`(модельований АРІ запит). Після того, як ви отримаєте (pretend) дані, відправте дію `receivedData()`, у якій передасте ці дані. Тепер ви знаєте, як опрацьовувати асинхронні дії у Redux. Все інше продовжує поводитися як і раніше.
# --hints--
Генератор дії `requestingData` має повернути об'єкт типу, що дорівнює значенню `REQUESTING_DATA`.
```js
assert(requestingData().type === REQUESTING_DATA);
```
Генератор дії `receivedData` має повернути об'єкт типу, що дорівнює значенню `RECEIVED_DATA`.
```js
assert(receivedData('data').type === RECEIVED_DATA);
```
`asyncDataReducer` має бути функцією.
```js
assert(typeof asyncDataReducer === 'function');
```
Відправлення генератора дії `requestingData` має оновити зберігання властивості `state` для отримання `true`.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(requestingData());
const reqState = store.getState();
return initialState.fetching === false && reqState.fetching === true;
})()
);
```
Посилання `handleAsync` має спочатку відправити дію про запит даних, а потім, після затримки, відправити отримані дані.
```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: Використання оператора розширення в масивах
challengeType: 6
forumTopicId: 301452
dashedName: use-the-spread-operator-on-arrays
---
# --description--
Одним із рішень від ES6, щоб забезпечити стан незмінності в Redux, є оператор розширення: `...`. Оператор розширення має велику кількість додатків, один з яких добре підходить для попереднього завдання, яке полягає в тому, щоб створити новий масив із масиву, який вже існує. Цей синтаксис є відносно новий, але його часто використовують. На приклад, якщо ви маєте масив `myArray` і записано:
```js
let newArray = [...myArray];
```
`newArray` - це тепер копія для `myArray`. Обидва масиви залишаються окремо існувати в пам'яті. Якщо ви виконуєте зміну, наприклад, `newArray.push(5)`, то `myArray` не зміниться. `...` ефективно *spreads* значення `myArray` в новому масиві. Щоб скопіювати масив, але і ще додати додаткове значення в цей новий масив, ви маєте написати `[...myArray, 'new value']`. Це буде повертати новий масив, який складений із значень в `myArray` і рядок `new value` як останнє значення. Синтаксис розширення може використовуватися декілька разів в складі такого масиву, але важливо звернути увагу на те, що він робить лише неглибоку копію масиву. Інакше кажучи, він лише забезпечує незмінні операції з масивом для одновимірного масиву.
# --instructions--
Оператор розширення використовується для того, щоб повернути нову копію тоді, коли додається запис.
# --hints--
Сховище Redux повинне існувати і ініціалізуватися із станом, який дорівнює `["Do not mutate state!"]`.
```js
assert(
(function () {
const initialState = store.getState();
return (
Array.isArray(initialState) === true &&
initialState[0] === 'Do not mutate state!'
);
})()
);
```
Обидві `addToDo` і `immutableReducer` мають бути функціями.
```js
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
```
Коли у Redux сховище відправляєте дію типу `ADD_TO_DO`, ви повинні додати `todo` і не можете змінювати стан.
```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);
})()
);
```
Оператор розповсюдження має використовуватися для повернення нового стану.
```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: Створіть лічильник із Redux
challengeType: 6
forumTopicId: 301453
dashedName: write-a-counter-with-redux
---
# --description--
Тепер ви освоїли всі основні принципи Redux! Ви побачили як створювати дії та генератори дії, сховище Redux, як відправляти дії у сховище та як розробляти оновлення станів за допомогою чистих перетворювачів. Ви навіть побачили, як керувати складним станом за допомогою елементів перетворювача та обробляти асинхронні дії. Ці приклади є прості, але ці концепти є ключовими принципами Redux. Якщо ви їх добре розумієте, тоді ви вже готові розпочати створення власного додатка Redux. Наступні завдання охоплюють деякі деталі щодо незмінності `state`, але для початку ось огляд усього, що ви вивчили до цього часу.
# --instructions--
У цьому уроці ви створите простий лічильник із допомогою Redux з нуля. Основна частина надана в редакторі коду, але вам доведеться заповнити деталі! Використовуйте назви, що надаються, і визначте генератори дії `incAction` та `decAction`, типи дії `counterReducer()`, `INCREMENT` та `DECREMENT`, і зрештою `store` Redux. Після завершення ви зможете надіслати дії `INCREMENT` чи `DECREMENT` для того, щоб збільшити чи зменшити стан, який зберігається у `store`. Удачі вам у створенні першого додатку Redux!
# --hints--
Генератор дії `incAction` має повернути об'єкт дії з `type`, рівним значенню `INCREMENT`
```js
assert(incAction().type === INCREMENT);
```
Генератор дії `decAction` має повернути об'єкт дії з `type`, рівним значенню `DECREMENT`
```js
assert(decAction().type === DECREMENT);
```
Сховище Redux повинне ініціалізуватися із `state`, що дорівнює 0.
```js
assert(store.getState() === 0);
```
Відправлення `incAction` у сховище Redux має збільшити `state` на 1.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(incAction());
const incState = store.getState();
return initialState + 1 === incState;
})()
);
```
Відправлення `decAction` у сховище Redux має зменшити `state` на 1.
```js
assert(
(function () {
const initialState = store.getState();
store.dispatch(decAction());
const decState = store.getState();
return initialState - 1 === decState;
})()
);
```
`counterReducer` має бути функцією
```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);
```