предисловие
- использовать в проекте
loading
, обычно в компоненте с переменной (например,isLoading
), чтобы сохранить данные запросаloading
статус, запросapi
бывший генералisLoading
установлено значениеtrue
,проситьapi
позжеisLoading
установлено значениеfalse
, так что реализацияloading
Государственный контроль, такой как следующий код:
import { Spin, message } from 'antd';
import { Bind } from 'lodash-decorators';
import * as React from 'react';
import * as api from '../../services/api';
class HomePage extends React.Component {
state = {
isLoading: false,
homePageData: {},
};
async componentDidMount () {
try {
this.setState({ isLoading: true }, async () => {
await this.loadDate();
});
} catch (e) {
message.error(`获取数据失败`);
}
}
@Bind()
async loadDate () {
const homePageData = await api.getHomeData();
this.setState({
homePageData,
isLoading: false,
});
}
render () {
const { isLoading } = this.state;
return (
<Spin spinning={isLoading}>
<div>hello world</div>
</Spin>
);
}
}
export default HomePage;
- Однако для большого проекта, если каждый запрос
api
Написание кода, подобного приведенному выше, очевидно, приведет к тому, что в проекте будет слишком много повторяющегося кода, что не способствует сопровождению проекта. Поэтому глобальное хранилище описано нижеloading
государственное решение.
идеи
- упаковка
fetch
Запрос (портал 👉:Процесс настройки проекта react + typescript) и соответствующие запросы данных, связанные сapi
- использовать
mobx
делать государственное управление - Используйте декоратор
@initLoading
реализоватьloading
Изменение и сохранение состояния
Запас знаний
- Введение в этот раздел и последующие подразделыКодНекоторые сопутствующие базовые знания, если вы их освоили, можете сразу пропустить🚶🚶🚶.
@Decorator
- Основная функция декоратора заключается в расширении некоторых новых поведений к существующему методу или классу вместо непосредственного изменения самого метода или класса, что можно просто понимать как ненавязчивую модификацию поведения.
- Декоратор может не только украшать класс, но и украшать свойства класса (идея этой статьи). Как и в приведенном ниже коде, декоратор
readonly
для украшенияname
метод.
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
- функция декоратора
readonly
Всего можно принять три параметра:- первый параметр
target
является прототипом объекта класса, который в данном случаеPerson.prototype
, первоначальное намерение декоратора состоит в том, чтобы «украсить» экземпляр класса, но экземпляр еще не был сгенерирован в это время, поэтому он может украсить только прототип (это отличается от украшения класса, в этом случаеtarget
параметр относится к самому классу) - второй параметр
name
имя свойства, которое нужно украсить - третий параметр
descriptor
это объект описания для этого свойства
- первый параметр
function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor);
- Приведенный выше код показывает, что функция декоратора
readonly
изменит объект описания атрибута (descriptor
), а измененный объект описания затем используется для определения свойств. - следующее
@log
Декоратор, который может играть роль вывода логов:
class Math {
@log
add(a, b) {
return a + b;
}
}
function log(target, name, descriptor) {
var oldValue = descriptor.value;
descriptor.value = function() {
console.log(`Calling ${name} with`, arguments);
return oldValue.apply(this, arguments);
};
return descriptor;
}
const math = new Math();
// passed parameters should get logged now
math.add(2, 4);
- Приведенное выше описание кода, декоратор
@log
Роль заключается в выполнении один раз перед выполнением исходной операции.console.log
, чтобы достичь цели вывода журнала.
mobx
-
Управление состоянием в проектах не используется
redux
вместо этого используйтеmobx
, Причина в том, чтоredux
Очень сложно написать:- Если вы хотите написать асинхронный метод и обработать его
side-effects
, использоватьredux-saga
илиredux-thunk
Для выполнения асинхронной обработки бизнес-логики - Если для повышения производительности необходимо ввести
immutable
Соответствующие гарантии библиотекиstore
производительность, сreselect
сделать механизм кэширования
- Если вы хотите написать асинхронный метод и обработать его
-
redux
Альтернативаmobx
, в официальной документации рекомендуется использоватьRootStore
связать всеStore
, который разрешает крестStore
Проблема вызова и может кэшировать источники данных нескольких модулей одновременно. -
в проекте
stores
хранится в каталогеindex.ts
код показывает, как показано ниже:
import MemberStore from './member';
import ProjectStore from './project';
import RouterStore from './router';
import UserStore from './user';
class RootStore {
Router: RouterStore;
User: UserStore;
Project: ProjectStore;
Member: MemberStore;
constructor () {
this.Router = new RouterStore(this);
this.User = new UserStore(this);
this.Project = new ProjectStore(this, 'project_cache');
this.Member = new MemberStore(this);
}
}
export default RootStore;
- о
mobx
Использование можно найти в документации 👉китайская документация mobx, здесь не приводится.
Код
- вышеупомянутая пара
loading
Код, связанный с контролем состояния, не имеет ничего общего с логикой взаимодействия самого компонента, если есть еще однотипные операции, требующие добавления дублирующего кода, то это явно неэффективно, а затраты на обслуживание слишком высоки. - Таким образом, эта статья создаст
initLoading
декоратор для упаковкиloading
Методы класса для сохранения и изменения состояния. - Основная идея заключается в использовании
store
контроль и хранениеloading
Статус, в частности:- установить один
BasicStore
класс, пиши внутриinitLoading
декоратор - необходимо использовать глобальные
loading
состояние различных модулейStore
нужно унаследоватьBasicStore
классы, реализующие различныеStore
междуloading
"Карантинная" обработка состояний - использовать
@initLoading
Обертка декоратора должна бытьloading
Различные модули, в которых состояние сохраняется и изменяетсяStore
метод в - Приобретение компонентов
Store
сохраненный глобальныйloading
государство
- установить один
- Советы: Конкретный процесс 👆 лучше понять код 👇.
Реализация декоратора @initLoading
- в проекте
stores
новый каталогbasic.ts
файл со следующим содержимым:
import { action, observable } from 'mobx';
export interface IInitLoadingPropertyDescriptor extends PropertyDescriptor {
changeLoadingStatus: (loadingType: string, type: boolean) => void;
}
export default class BasicStore {
@observable storeLoading: any = observable.map({});
@action
changeLoadingStatus (loadingType: string, type: boolean): void {
this.storeLoading.set(loadingType, type);
}
}
// 暴露 initLoading 方法
export function initLoading (): any {
return function (
target: any,
propertyKey: string,
descriptor: IInitLoadingPropertyDescriptor,
): any {
const oldValue = descriptor.value;
descriptor.value = async function (...args: any[]): Promise<any> {
let res: any;
this.changeLoadingStatus(propertyKey, true); // 请求前设置loading为true
try {
res = await oldValue.apply(this, args);
} catch (error) {
// 做一些错误上报之类的处理
throw error;
} finally {
this.changeLoadingStatus(propertyKey, false); // 请求完成后设置loading为false
}
return res;
};
return descriptor;
};
}
- Как видно из приведенного выше кода,
@initLoading
Роль декоратора заключается в том, чтобы обернуть имя свойства метода.propertyKey
хранятся в отслеживаемых данныхstoreLoading
, установите метод-оболочку обернутого метода перед запросомloading
заtrue
, который устанавливает метод-оболочку для обернутого метода, когда запрос выполнен успешно/ошибкаloading
заfalse
.
Магазин наследует от BasicStore
- от
ProjectStore
Например, если модуль имеетloadProjectList
метод используется для извлечения данных списка элементов, и этот метод должен использоватьloading
, то проектstores
в каталогеproject.ts
Содержимое файла следующее:
import { action, observable } from 'mobx';
import * as api from '../services/api';
import BasicStore, { initLoading } from './basic';
export default class ProjectStore extends BasicStore {
@observable projectList: string[] = [];
@initLoading()
@action
async loadProjectList () {
const res = await api.searchProjectList(); // 拉取 projectList 的 api
runInAction(() => {
this.projectList = res.data;
});
}
}
используемые компоненты
- Предположим, правильно
HomePage
Компонент добавляет данные при загрузкеloading
Отображение состояния:
import { Spin } from 'antd';
import { inject, observer } from 'mobx-react';
import * as React from 'react';
import * as api from '../../services/api';
@inject('store')
@observer
class HomePage extends React.Component {
render () {
const { projectList, storeLoading } = this.props.store.ProjectStore;
return (
<Spin spinning={storeLoading.get('loadProjectList')}>
{projectList.length &&
projectList.map((item: string) => {
<div key={item}>
{item}
</div>;
})}
</Spin>
);
}
}
export default HomePage;
- Приведенный выше код используется
mobx-react
из@inject
и@observer
декоратор для упаковкиHomePage
компоненты, их роль заключается вHomePage
Преобразованы в отзывчивые компоненты и введеныProvider
(в файле ввода) предоставленоstore
к этому компонентуprops
, так что можно пройтиthis.props.store
стать другимStore
данные модуля.-
@observer
Функция/декоратор может быть использована для добавленияReact
Компоненты превратились в реактивные компоненты -
@inject
Декоратор эквивалентенProvider
Компонент более высокого порядка, который можно использовать изReact
изcontext
выбирать средиstore
в видеprops
передается целевому компоненту
-
- наконец прошло
this.props.store.ProjectStore.storeLoading.get('loadProjectList')
получитьProjectStore
Глобальные переменные хранятся в модуляхloading
государство.
Суммировать
- Решение, описанное в этой статье, дает два преимущества, которые можно получить во время запроса.
loading
Отображение состояния; при возникновении ошибки ее можно обработать глобально (отчет об ошибках и т. д.). - Рациональное использование декораторов может значительно повысить эффективность разработки, а инкапсуляция и уточнение некоторых нелогически связанных кодов может помочь нам быстро выполнять повторяющиеся задачи и экономить время.