Я новичок в MST и с трудом нахожу больше примеров с асин c действиями. У меня есть API, который будет возвращать разные данные в зависимости от параметров, которые вы передаете ему. В этом случае API может вернуть массив фотографий или учебных пособий. Я установил свои начальные значения для магазина следующим образом:
data: {
photos: [],
tutorials: []
}
В настоящее время я использую applySnapshot
для обновления магазина и, в конечном итоге, это вызовет повторную визуализацию моего компонента React. Чтобы отобразить как фотографии, так и учебники, мне нужно вызвать API дважды (один раз с параметрами для фотографий и второй раз для уроков). Я сталкиваюсь с проблемой, когда снимок из первого обновления показывает, что фотографии и учебные пособия имеют одинаковые значения и только во втором обновлении я получаю правильные значения. Я, вероятно, неправильно использую applySnapshot
для повторного рендеринга моих компонентов React. Я хотел бы знать лучший / правильный способ сделать это. Каков наилучший способ перерисовать мои компоненты React после того, как API дал ответ. Любые предложения приветствуются
Я настроил свой магазин следующим образом:
import { RootModel } from '.';
import { onSnapshot, getSnapshot, applySnapshot } from 'mobx-state-tree';
export const setupRootStore = () => {
const rootTree = RootModel.create({
data: {
photos: [],
tutorials: []
}
});
// on snapshot listener
onSnapshot(rootTree, snapshot => console.log('snapshot: ', snapshot));
return { rootTree };
};
Я создал следующую модель с действием asyn c, используя генераторы:
import {types,Instance,applySnapshot,flow,onSnapshot} from 'mobx-state-tree';
const TestModel = types
.model('Test', {
photos: types.array(Results),
tutorials: types.array(Results)
})
.actions(self => ({
fetchData: flow(function* fetchData(param) {
const results = yield api.fetch(param);
applySnapshot(self, {
...self,
photos: [... results, ...self.photos],
tutorials: [... results, ...self.tutorials]
});
})
}))
.views(self => ({
getPhoto() {
return self.photos;
},
getTutorials() {
return self.tutorials;
}
}));
const RootModel = types.model('Root', {
data: TestModel
});
export { RootModel };
export type Root = Instance<typeof RootModel>;
export type Test = Instance<typeof TestModel>;
Реагирующий компонент для Photos.tsx
import React, { Component } from 'react';
import Spinner from 'components/Spinner';
import { Root } from '../../stores';
import { observer, inject } from 'mobx-react';
interface Props {
rootTree?: Root
}
@inject('rootTree')
@observer
class Photos extends Component<Props> {
componentDidMount() {
const { rootTree } = this.props;
if (!rootTree) return null;
rootTree.data.fetchData('photo');
}
componentDidUpdate(prevProps) {
if (prevProps.ctx !== this.props.ctx) {
const { rootTree } = this.props;
if (!rootTree) return null;
rootTree.data.fetchData('photo');
}
}
displayPhoto() {
const { rootTree } = this.props;
if (!rootTree) return null;
// calling method in MST view
const photoResults = rootTree.data.getPhoto();
if (photoResults.$treenode.snapshot[0]) {
return (
<div>
<div className='photo-title'>{'Photo'}</div>
{photoResults.$treenode.snapshot.map(Item => (
<a href={photoItem.attributes.openUrl} target='_blank'>
<img src={photoItem.url} />
</a>
))}
</div>
);
} else {
return <Spinner />;
}
}
render() {
return <div className='photo-module'>{this.displayPhoto()}</div>;
}
}
export default Photos;
Аналогично Tutorials.tsx выглядит так:
import React, { Component } from 'react';
import Spinner from '';
import { Root } from '../../stores';
import { observer, inject } from 'mobx-react';
interface Props {
rootTree?: Root;
}
@inject('rootTree')
@observer
class Tutorials extends Component<Props> {
componentDidMount() {
if (this.props.ctx) {
const { rootTree } = this.props;
if (!rootTree) return null;
rootTree.data.fetchData('tuts');
}
}
componentDidUpdate(prevProps) {
if (prevProps.ctx !== this.props.ctx) {
const { rootTree } = this.props;
if (!rootTree) return null;
rootTree.search.fetchData('tuts');
}
}
displayTutorials() {
const { rootTree } = this.props;
if (!rootTree) return null;
// calling method in MST view
const tutResults = rootTree.data.getTutorials();
if (tutResults.$treenode.snapshot[0]) {
return (
<div>
<div className='tutorials-title'>{'Tutorials'}</div>
{tutResults.$treenode.snapshot.map(tutorialItem => (
<a href={tutorialItem.attributes.openUrl} target='_blank'>
<img src={tutorialItem.url} />
</a>
))}
</div>
);
} else {
return <Spinner />;
}
}
render() {
return <div className='tutorials-module'>{this.displayTutorials()}</div>;
}
}
export default Tutorials;