chore(i18n,curriculum): processed translations - new ukrainian (#44447)
This commit is contained in:
@@ -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);
|
||||
```
|
@@ -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);
|
||||
```
|
@@ -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);
|
||||
```
|
@@ -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'
|
||||
}
|
||||
```
|
@@ -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;
|
||||
};
|
||||
```
|
@@ -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());
|
||||
```
|
@@ -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();
|
||||
```
|
@@ -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'
|
||||
}
|
||||
};
|
||||
```
|
@@ -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);
|
||||
```
|
@@ -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});
|
||||
```
|
@@ -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);
|
||||
```
|
@@ -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());
|
||||
```
|
@@ -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'
|
||||
}
|
||||
};
|
||||
```
|
@@ -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
|
||||
}
|
||||
};
|
||||
```
|
@@ -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)
|
||||
);
|
||||
```
|
@@ -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);
|
||||
```
|
@@ -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);
|
||||
```
|
Reference in New Issue
Block a user