Высокий старт будет компенсируется легкими дополнениями. Следующие 2 порции задач будут гораздо проще, не волнуйтесь из-за объема 😉.
Мы разрабатываем клиент для github, где можно гулять по друзьям, репозиториям, смотреть issues, комиты и так далее.
Для начала мы реализуем простой функционал хождения по последователям. Я расскажу, какие файлы нужно создать, и что именно протестировать, но всю работу вам прийдется выполнять самим.
├── api.js
├── components
│ ├── AppRouter
│ ├── Follower
│ ├── Followers
│ ├── Login
│ ├── PrivateRoute
│ └── UserPage
├── index.css
├── index.js
├── ducks
│ ├── auth.js
│ ├── index.js
│ └── users.js
├── sagas
│ ├── auth.js
│ ├── index.js
│ └── users.js
├── setupTests.js
└── store.js
Файл api содержит логику по работе с токеном авторизации, распологать там ключ нужно с помощью саги
auth
.
- Обычно все проекты начинаются с роутера, по этому надо начать написание компонента
AppRouter
, сreact-router-dom
. - Для компоненты
AppRouter
нужно:- Написать роутинг, но пока разместить 2 роута для
/users/me
и/login
- Используйте Redirect, а также вам понадобится компонент PrivateRoute, который мы уже писали.
- Написать роутинг, но пока разместить 2 роута для
- Компонент
Login
, в котором происходит сохранение токена для github - Написать компонент
UserPage
, который содержит верстку аватара пользователя, информацию о пользователе. При монтировании нужно делать запрос на получение информации о пользователе. В основной верстке должен быть:- аватар пользователя,
- login пользователя,
- количество фаловеров пользователя
- Написать экшены, редьюсеры для получения данных о пользователе. При новом запросе пользователя, нужно удалять данные о предыдущем пользователе.
- Для работы с localstorage нужно проверять наличие ключа в localstorage при авторизации:
function* authFlow() { while (true) { const isAuthorized = yield select(getIsAuthorized); const localStorageToken = yield call(getTokenFromLocalStorage); let token; if (!isAuthorized && localStorageToken) { token = localStorageToken; yield put(authorize()); } else { const action = yield take(authorize); token = action.payload; } yield call(setTokenApi, token); yield call(setTokenToLocalStorage, token); yield take(logout); yield call(removeTokenFromLocalStorage); yield call(clearTokenApi); } }
Когда вам нужно приступать к написанию новых проектов, начинайте написание проекта с первой компоненты, которая выводит вам что то простое, например пустой div. Посмотрите, какие данные и логику нужно расположить на странице, в случае с UserPage, нужно получить данные по пользователю, значит отправить экшен о получении данных. Так как нужно совершить запрос, вам понадобится 3 экшена, флаги сетевых запросов, редьюсер для данных и для ошибки. После отправки экшена, нужно убедиться что экшен действительно отправляется, это удобно делать через redux devtools. После того как экшен отправляется, можно приступить к написанию саги, которая обрабатывает запрос. Сага должна получать данные, и отправлять их в редьюсер. Как только вы увидете данные в редьюсере, можно приступать к написанию верстки данных. Следующие шаги повторяют пройденные, смотрим какие данные нужны, какие компоненты написать, как описать получение данных из сети.
Как работает авторизация?
Авторизация в этой домашней работе происходит с помощью токена который вы передаете в форме, на
странице login
. Авторизация работает следующим образом, пользователь должен ввести токен, после
нажатия кнопки Еnter, компонент отправляет экшеном токен, который с помощью саги передается в модуль
api. Теперь все запросы будут содержать ключ авторизации, и гитхаб не будет ограничивать сетевые
запросы приложения, но даже с ключом там есть лимит на 5000 запросов, так что не удивляйтесь, если
вас заблокируют на 10-15 минут при очень большом количестве запросов.
Как подключить спиннер?
Если вы хотите такой же спиннер как примере кода, то используйте следующий код:
import Spinner from 'react-svg-spinner';
...
if (isFetching) {
return <Spinner size="64px" color="fuchsia" gap={5} />;
}
-
Для компоненты
AppRouter
нужно написать тесты:- Проверить наличие
Switch
, - Проверить наличие компоненты
<PrivateRoute path="/user/me" />
, - Проверить наличие компоненты
<PrivateRoute path="/user/:name" />
, - Проверить наличие комполненты
<Route path="/login" />
,
- Проверить наличие
-
Написать тесты для компоненты UserPage:
- Проверить наличие метода componentDidUpdate,
- Проверить наличие спинера/лоадера если props.isFetching === true,
- Проверить наличие сообщения об отсутствии пользователя если isFetching === false && user == null,
- В основной верстке должен быть:
- аватар пользователя,
- login пользователя,
- количество фаловеров пользователя,
- компонент Followers с передачей login через props.
-
Написать тесты для редьюсера
users
:- Проверить, что экшены
fetchUserRequest
,fetchUserSuccess
,fetchUserFailure
:- изменяют флаг
isFetching
, - очищают поле
data
, если приходит экшенfetchUserRequest
, - наполняют данными
data
, если приходит экшенfetchUserSuccess
, - очищают поле
error
, если приходит экшенfetchUserRequest
илиfetchUserSuccess
, - наполняют данными
error
, если приходит экшенfetchUserFailure
.
- изменяют флаг
- Проверить, что экшены
-
Написать компонент
Followers
. При монтировании этого компонента необходимо делать запрос на последователей пользователя. Очень удобно передаватьlogin
(идентификатор пользователя) текущего пользователя отUserPage
кFollowers
через props. Не забудьте проверку наisFetching
. -
Написать тесты для компоненты
Followers
:- Проверить наличие метода класса
componentDidMount
, - Проверить наличие лоадера/спинера, если
isFetcing === true
, - Проверить что возвращаются компоненты
Followers
в том количестве, в котором передаются в props.followers.
- Проверить наличие метода класса
-
Написать экшены, редьюсеры(саги присутствуют) для получения последователей(followers).
-
Написать тесты для редьюсера
followers
:- Проверить, что экшены
fetchFollowersRequest
,fetchFollowersSuccess
,fetchFollowersFailure
:- изменяют флаг
isFetching
, - очищают поле
ids
, если приходит экшенfetchFollowersRequest
, - наполняют данными
ids
, если приходит экшенfetchFollowersSuccess
, - очищают поле
error
, если приходит экшенfetchFollowersRequest
илиfetchFollowersSuccess
, - наполняют данными
error
, если приходит экшенfetchFollowersFailure
.
- изменяют флаг
- Проверить, что экшены
-
Компонент
Follower
очень простой, он содержит аватар и ссылку на страницу пользователя. -
Написать тесты для компоненты
Follower
:- Проверить наличие аватара,
- Проверить наличие
login
пользователя переданного через props, - Проверить что ссылка с логина пользователя ведет на
/user/{user.login}
.
Как писать тесты для компонент с connect()()
Не нужно импортировать в тест компонент обернутый в метод connect, нужно делать отдельный экспорт компоненты, без обертки в метод connect, и тестировать только такой компонент.// App.js
export class App extends Component {
...
}
export default connect()(App)
// App.test.js
import {App} from './App'
...
Я добавил отдельный уровень сетевых запросов через сагу
request
, а так же экшены и редьюсерnetwork
. Это удобный маневр, если нужно делать централизованную обработку сетевых запросов, в данном случае, идет обработка всех сетевых запросов, и в том случае, если ответ содержит 401 статус, соответствующий ошибке токена — происходит logout. Все сетевые запросы я делаю следующим образом:response = yield call(requestFlow, getUserInformation, action.payload);
- Добавить кнопку logout и вывод сетевых ошибок в компоненте
AppRouter
. - Написать тесты для
request
- Переписать саги выполняющие сетевые запросы с использованием
request
- Выводить сообщение сетевой ошибки в самом верхнем компоненте вместо всего дерева компонент, в случае возникновения ошибки.