Javascript MobX状态树异步操作和重新呈现React组件
我是MST新手,很难找到更多异步操作的示例。我有一个api,它将根据传递给它的参数返回不同的数据。在这种情况下,api可以返回一组照片或教程。我为商店设置了初始值,如下所示:Javascript MobX状态树异步操作和重新呈现React组件,javascript,reactjs,mobx,mobx-state-tree,Javascript,Reactjs,Mobx,Mobx State Tree,我是MST新手,很难找到更多异步操作的示例。我有一个api,它将根据传递给它的参数返回不同的数据。在这种情况下,api可以返回一组照片或教程。我为商店设置了初始值,如下所示: data: { photos: [], tutorials: [] } import React, { Component } from 'react'; import Spinner from ''; import { Root } from '../../stores'; import { observe
data: {
photos: [],
tutorials: []
}
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;
目前,我正在使用applySnapshot
更新存储,并最终触发React组件的重新渲染。为了同时显示照片和教程,我需要调用api两次(一次调用照片参数,第二次调用教程参数)。我遇到了一个问题,第一次更新的快照显示照片和教程具有相同的值,只有在第二次更新时,我才能获得正确的值。我可能误用了applySnapshot
来重新渲染我的组件。我想知道更好/正确的方法。在api生成repsonse后,重新呈现React组件的最佳方式是什么。任何建议都将不胜感激
我的店铺是这样设置的:
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 };
};
我使用生成器创建了具有异步操作的以下模型:
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>;
类似地,Tutorials.tsx也是这样:
data: {
photos: [],
tutorials: []
}
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;
import React,{Component}来自'React';
从“”导入微调器;
从“../../stores”导入{Root};
从“mobx react”导入{observer,inject};
界面道具{
根树:根;
}
@注入('rootTree')
@观察者
类教程扩展了组件{
componentDidMount(){
if(this.props.ctx){
const{rootTree}=this.props;
如果(!rootTree)返回null;
rootTree.data.fetchData('tuts');
}
}
componentDidUpdate(prevProps){
if(prevProps.ctx!==this.props.ctx){
const{rootTree}=this.props;
如果(!rootTree)返回null;
rootTree.search.fetchData('tuts');
}
}
显示教程(){
const{rootTree}=this.props;
如果(!rootTree)返回null;
//MST视图中的调用方法
const tutResults=rootTree.data.getTutorials();
if(结果$treenode.snapshot[0]){
返回(
{'Tutorials'}
{tutResults.$treenode.snapshot.map(tutorialItem=>(
))}
);
}否则{
返回;
}
}
render(){
返回{this.displaytourials()};
}
}
导出默认教程;
在这种情况下,为什么要使用applySnapshot
?我认为没有必要。只需在操作中根据需要分配数据:
.actions(self => ({
//If you're fetching both at the same time
fetchData: flow(function* fetchData(param) {
const results = yield api.fetch(param);
//you need cast() if using Typescript otherwise I think it's optional
self.photos = cast([...results.photos, ...self.photos])
//do you really intend to prepend the results to the existing array or do you want to overwrite it with the sever response?
self.tutorials = cast(results.tutorials)
})
}))
或者,如果您需要发出两个单独的请求来获取数据,那么最好执行两个不同的操作
.actions(self => ({
fetchPhotos: flow(function* fetchPhotos(param) {
const results = yield api.fetch(param)
self.photos = cast([... results, ...self.photos])
}),
fetchTutorials: flow(function* fetchTutorials(param) {
const results = yield api.fetch(param)
self.tutorials = cast([... results, ...self.tutorials])
}),
}))
无论如何,您似乎不需要
applySnapshot
。只要根据需要在操作中分配数据即可。在异步操作中分配数据没有什么特别的 在这种情况下,为什么要使用applySnapshot
?我认为没有必要。只需在操作中根据需要分配数据:
.actions(self => ({
//If you're fetching both at the same time
fetchData: flow(function* fetchData(param) {
const results = yield api.fetch(param);
//you need cast() if using Typescript otherwise I think it's optional
self.photos = cast([...results.photos, ...self.photos])
//do you really intend to prepend the results to the existing array or do you want to overwrite it with the sever response?
self.tutorials = cast(results.tutorials)
})
}))
或者,如果您需要发出两个单独的请求来获取数据,那么最好执行两个不同的操作
.actions(self => ({
fetchPhotos: flow(function* fetchPhotos(param) {
const results = yield api.fetch(param)
self.photos = cast([... results, ...self.photos])
}),
fetchTutorials: flow(function* fetchTutorials(param) {
const results = yield api.fetch(param)
self.tutorials = cast([... results, ...self.tutorials])
}),
}))
无论如何,您似乎不需要
applySnapshot
。只要根据需要在操作中分配数据即可。在异步操作中分配数据没有什么特别的 虽然此评论与MobX无关,但我强烈建议您对教程和照片使用单独的端点。它们是两种不同的实体类型,这只会导致混淆(并且很难维护代码)。对不起,我没办法。我希望有人能带来更多的MobX经验,祝你好运!虽然此评论与MobX无关,但我强烈建议您对教程和照片使用单独的端点。它们是两种不同的实体类型,这只会导致混淆(并且很难维护代码)。对不起,我没办法。我希望有人能带来更多的MobX经验,祝你好运!