使用 Mobx 在服务器端异步加载组件数据
Loading component data asynchronously server side with Mobx
我在弄清楚如何让反应组件具有基于异步获取的数据的初始状态时遇到问题。
MyComponent 从 API 获取数据并通过 Mobx action
.
设置其内部 data
属性
客户端,componentDidMount
被调用并获取数据然后设置并正确呈现。
import React from 'react';
import { observer } from 'mobx-react';
import { observable, runInAction } from 'mobx';
@observer
export default class MyComponent extends React.Component {
@observable data = [];
async fetchData () {
loadData()
.then(results => {
runInAction( () => {
this.data = results;
});
});
}
componentDidMount () {
this.fetchData();
}
render () {
// Render this.data
}
}
我知道在服务器上,componentDidMount
没有被调用。
我的服务器有这样的东西:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { useStaticRendering } from 'mobx-react';
import { match, RouterContext } from 'react-router';
import { renderStatic } from 'glamor/server'
import routes from './shared/routes';
useStaticRendering(true);
app.get('*', (req, res) => {
match({ routes: routes, location: req.url }, (err, redirect, props) => {
if (err) {
console.log('Error', err);
res.status(500).send(err);
}
else if (redirect) {
res.redirect(302, redirect.pathname + redirect.search);
}
else if (props) {
const { html, css, ids } = renderStatic(() => renderToString(<RouterContext { ...props }/>));
res.render('../build/index', {
html,
css
});
}
else {
res.status(404).send('Not found');
}
})
})
我看过许多帖子,其中计算初始存储并通过 Provider
组件传递。我的组件已呈现,但它们的状态未初始化。我不想将此数据保存在商店中,并希望它在组件的本地范围内。怎么办?
对于服务器端渲染,您需要先获取数据,然后再渲染。组件在 SSR 期间没有生命周期,只会渲染一次字符串,但不能响应任何未来的变化。
由于您的数据获取方法是异步的,这意味着它永远不会影响输出,因为组件已经被写入。所以答案是先获取数据,然后挂载和渲染组件,中间不使用任何异步机制(promises、async 等)。我认为将 UI 和数据获取逻辑分开是一个很好的做法,原因有很多(SSR、路由、测试),请参阅 this blog。
另一种方法是创建组件树,但要等待序列化,直到所有承诺都已解决。这就是例如 mobx-server-wait 使用的方法。
我在弄清楚如何让反应组件具有基于异步获取的数据的初始状态时遇到问题。
MyComponent 从 API 获取数据并通过 Mobx action
.
data
属性
客户端,componentDidMount
被调用并获取数据然后设置并正确呈现。
import React from 'react';
import { observer } from 'mobx-react';
import { observable, runInAction } from 'mobx';
@observer
export default class MyComponent extends React.Component {
@observable data = [];
async fetchData () {
loadData()
.then(results => {
runInAction( () => {
this.data = results;
});
});
}
componentDidMount () {
this.fetchData();
}
render () {
// Render this.data
}
}
我知道在服务器上,componentDidMount
没有被调用。
我的服务器有这样的东西:
import React from 'react';
import { renderToString } from 'react-dom/server';
import { useStaticRendering } from 'mobx-react';
import { match, RouterContext } from 'react-router';
import { renderStatic } from 'glamor/server'
import routes from './shared/routes';
useStaticRendering(true);
app.get('*', (req, res) => {
match({ routes: routes, location: req.url }, (err, redirect, props) => {
if (err) {
console.log('Error', err);
res.status(500).send(err);
}
else if (redirect) {
res.redirect(302, redirect.pathname + redirect.search);
}
else if (props) {
const { html, css, ids } = renderStatic(() => renderToString(<RouterContext { ...props }/>));
res.render('../build/index', {
html,
css
});
}
else {
res.status(404).send('Not found');
}
})
})
我看过许多帖子,其中计算初始存储并通过 Provider
组件传递。我的组件已呈现,但它们的状态未初始化。我不想将此数据保存在商店中,并希望它在组件的本地范围内。怎么办?
对于服务器端渲染,您需要先获取数据,然后再渲染。组件在 SSR 期间没有生命周期,只会渲染一次字符串,但不能响应任何未来的变化。
由于您的数据获取方法是异步的,这意味着它永远不会影响输出,因为组件已经被写入。所以答案是先获取数据,然后挂载和渲染组件,中间不使用任何异步机制(promises、async 等)。我认为将 UI 和数据获取逻辑分开是一个很好的做法,原因有很多(SSR、路由、测试),请参阅 this blog。
另一种方法是创建组件树,但要等待序列化,直到所有承诺都已解决。这就是例如 mobx-server-wait 使用的方法。