我有一个使用reactjs和redux构建的简单应用程序。由于我刚开始学习redux,我在服务器端渲染时遇到了一些问题。
到目前为止我所拥有的是...... 客户端App.js呈现App组件。
render(
<Provider store={store}>
<App />
</Provider>,
document.body
);
应用程序组件:
const App = () => (
<div>
<SearchContainer />
<TodoContainer />
</div>
)
如果两个项都是容器,则SearchContainer从输入框获取输入,触发一个动作,该动作用于加载todo`s(来自远程休息服务)的消息。
现在我喜欢在服务器端加载页面加载上的那些todo,并在显示页面后显示它们。我该怎么办?有没有办法在实际显示页面之前不使用服务器端渲染和加载项目?
到目前为止,我发现的是routes.js文件:
const middleware = [ thunk ]
if (process.env.NODE_ENV !== 'production') {
middleware.push(createLogger())
}
const store = createStore(reducer,applyMiddleware(...middleware))
app.get('/', function(req, res) {
res.render('home',{
markup: ReactDOMServer.renderToString(
<Provider store={store}>
<App />
</Provider>
)
});
//Some code calling remote service goes here
这通常是加载和应用程序,但如何将加载的数据推送到TodoContainer?它应该是某种方式来分派消息,还是应该使用todos数组作为属性初始化App组件?
答案 0 :(得分:1)
您不需要服务器端渲染。
解决您遇到的问题的最常见方法是从componentDidMount
加载数据。在返回此数据之前,您需要显示某些内容,例如微调器或笨蛋或消息或空白页。这就是它的方式。您的应用程序不会是唯一一个带有加载指示符的应用程序......
但是,您还可以执行的操作是在发送页面之前获取数据服务器端,然后使用<{em> 将页面发送到<script>
标记中JSON.stringify
的帮助。
<script>
window.initialData = {
"myData": [ 1, 2, 3 ]
};
</script>
然后你可以用它来初始化商店。这使数据立即可用,并消除了对API端点的需求。
const store = createStore(reducer, window.initialData, applyMiddleware(...middleware));
您也可以使用相同的数据在服务器上呈现,但无论如何都不需要它。
最后,我想指出您要渲染到document.body
,这是一个坏主意,因为很多浏览器扩展和插件都会添加div或其他内容。 DOM满足自己的需求。 React并没有很好地发挥这些作用。它期望控制它传递的元素。最好只创建一个div
并将其渲染到其中。
答案 1 :(得分:0)
考虑一下你是否真的需要在todo app中使用SSR。主要的优点是改进了搜索引擎优化,你的应用程序准备好了一点(它已经渲染)。如果它不是很重,你可能想跳过它。
在实际显示页面之前,有没有办法不使用服务器端渲染和加载项目?
是的,例如,您可以调度获取数据的操作,并将其推送到componentWillMount
中的Redux状态。在数据不存在之前,您可以呈现某个加载指示符的null
。
答案 2 :(得分:0)
嗯,在这里获得了一些反应,redux,nodejs和其他一些客户端和服务器端技术的经验,这是我发现的以及它对我有用的方式。
react / redux应用程序中的服务器端呈现包含几个步骤: 1.在服务器上加载数据 2.将数据从服务器推送到客户端 3.将数据加载到redux存储
以下是上传'redux-polyglot'组件翻译的小例子。
routes.js [处理快速服务器请求]:
//...all of your imports goes here
import en_phrases from './resources/phrases/en'
app.get('/', async function(req, res) {
const store = createStore(reducers, applyMiddleware(...whatevermiddlewareyouneed))
return res.render('home', {
markup: ReactDOMServer.renderToString(
<Provider store={store}>
<App/>
</Provider>
),
otherPreloadedStateThanPhrases: JSON.stringify(...anythingelse)
phrases: JSON.stringify(en_phrases)
});
}
这里的'home'值是把手模板名称,其中包含:
<script type="application/json" id="phrases">
{{{ phrases }}}
</script>
然后,应用程序负责从“短语”脚本标记加载数据,并将其设置为默认语言,并提供多语言提供的功能。
app.js
const phrases = JSON.parse(document.getElementById('phrases').innerHTML);
const store = createStore(reducers, otherPreloadedStateThanPhrases, applyMiddleware(...middleware));
store.dispatch(setLanguage('en', phrases));
LoginContainer.js [从应用程序中使用的样本容器]
let LoginContainer = ({p}) => {
<span>{p.tc('login')}</span>
}
exports.LoginContainer = connect((state) => ()(translate(LoginContainer))
其中'login'是从服务器上的短语json加载的值: en.js
export default {
login: "Login"
}