Данная библиотека берет на себя совершение запросов на бэк. Записывает в store
состояние запросов, которые грузятся или провалились.
Предоставляет хуки: useIsLoading
и useIsError
.
Предоставляет хук: useDataSelector
, который автоматически берет данные.
Чтобы подключить библиотеку, необходимо модифицировать ваш store:
- Подключить
formControllerReducer
import {requestControllerReducer} from "react-redux-request-controller";
const combinedReducer = combineReducers({
requestController: requestControllerReducer, // подключение requestControllerReducer
user: userReducer,
contact: contactReducer,
});
- Записать функцию
getState
в window
window.getState = () => store.getState()
- rootUrl берется из
process.env.REACT_APP_SERVER_API_URL
, поэтому, скрипт для запуска приложения, должен выглядеть как-то так:
"start-develop": "PORT=3000 REACT_APP_SERVER_API_URL=http://11.111.111.1111:8000 react-scripts start",
- Авторизационный токен должен храниться в
window.token
-
requestController
Полагаю, имеет смысл вставить интерфейс.
interface IRequestController {
onSuccess?: (data: any) => void;
onFailed?: (errors: any | undefined) => void;
serialize?: (data: any) => void;
method: "POST" | "GET" | "DELETE" | "PUT";
id: string;
action: any;
url: string;
params?: object;
}
onFailed
- в случае, если запрос окончился ошибкой, вызовется без параметров.
Если статус ответа - 400, вызовется с данными, которые пришли с бэка.
serializer
- необходим, если вы хотите поменять структуру данных, которые пришли с бэка.
id
- уникальный идентификатор запроса. Если запрос на удаление или на обновление,
имеет смысл, id
записывать как-то так: updateItem24
, где 24 это id обновляемого компонента.
2) useIsLoading
&& useIsError
Принимают всего 1 параметр: id запроса.
3) getIsLoading
&& getIsError
Также принимают всего 1 параметр: id запроса.
4) useDataSelector
Принимает 3 параметра: selector, isLoading(функция, которая возвращает boolean), getDefaultFunction(функция, для взятия данных, которая оборачивается в dispatch).
###Конечный код
import {RootState, store} from "../store";
import {useDataSelector} from "../../utils/phoenix/useData";
import {createContact, deleteContactData, getContactData, updateContactData} from "./thunks";
import {IUser} from "../user/model";
import {getIsError, getIsLoading, useIsError, useIsLoading} from "react-redux-request-controller";
export const Contact = {
useData: () => useDataSelector(
(state: RootState) => state.contact.contact,
Contact.object.getIsLoading,
getContactData
) as Array<IContact> | null,
useIsLoading: () => useIsLoading('getContactData'),
useIsError: () => useIsError('getContactData'),
object: {
getData: () => store.getState().contact.contact as Array<IContact> | null,
getIsLoading: () => getIsLoading('getContactData'),
getIsError: () => getIsError('getContactData'),
},
options: {
create: (data:ICreateContact) => window.dispatch(createContact(data)),
update: (data:IUpdateContact) => window.dispatch(updateContactData(data)),
delete: (data:IDeleteContact) => window.dispatch(deleteContactData(data)),
}
}
export interface IContact {
id: string | number;
phone: string;
name: string;
user?: IUser;
}
//****************** Options interface ******************//
export interface ICreateContact {
phone: string;
name: string;
}
export interface IUpdateContact {
id?: string | number;
phone: string;
name: string;
}
export interface IDeleteContact {
id: string | number;
}
Эта библиотека создана, чтобы создавать model.ts
.
В данном файле почти нет логики.
Это лишь удобный интерфейс, с очень удобным синтаксисом, для взаимодействия с моделью Contact
.
Я считаю, что данный подход лучше, чем рандомно раскиданные экшены и селекторы.
Да и код
const userData = User.useData()
Куда более чистый и лаконичный, чем
const userData = useSelector(userDataSelector)
или
User.options.login(data)
лучше, чем
const dispatch = useDispatch()
dispatch(userLogin(data))