我在Route组件上使用静态fetchData方法…
const mapStateToProps = (state) => ({ posts: state.posts }) @connect(mapStateToProps) class Blog extends Component { static fetchData (dispatch) { return dispatch(fetchPosts()) } render () { return ( <PostsList posts={this.props.posts} /> ) } }
…并在服务器端的初始渲染之前收集所有承诺…
match({ routes,location },(error,redirectLocation,renderProps) => { const promises = renderProps.components .filter((component) => component.fetchData) .map((component) => component.fetchData(store.dispatch)) Promise.all(promises).then(() => { res.status(200).send(renderView()) }) })
它工作正常,服务器等待,直到我的所有承诺在渲染应用程序之前得到解决.
现在,在我的客户端脚本上,我正在做与服务器上类似的事情……
... function resolveRoute (props) { props.components .filter((component) => component.fetchData) .map((component) => component.fetchData(store.dispatch)) return <RouterContext {...props} /> } render(( <Provider store={store}> <Router history={browserHistory} routes={routes} render={resolveRoute} /> </Provider> ),document.querySelector('#app'))
它工作正常.但是,正如你可以推断的那样,在初始页面渲染中,静态fetchData被调用两次(一次在服务器上,一次在客户端上),我不希望这样.
关于如何解决这个问题有什么建议吗?建议?
我正在通过手机输入这个,所以我为缺乏格式而道歉.
原文链接:https://www.f2er.com/react/300880.html对于我的项目,我正在做与你类似的事情;我有一个静态的fetchData方法,我循环遍历renderProps中的组件,然后我调用静态方法并等待promises解析.
然后,我从我的redux商店调用get状态,对其进行字符串化,并将其传递给服务器上的渲染函数,以便它可以在客户端上渲染出初始状态对象.
从客户端,我只需抓住该初始状态变量并将其传递给我的redux商店.然后,Redux将处理使您的客户端存储与服务器上的存储匹配.从那里,您只需将您的商店转移到提供商,然后照常继续.您根本不需要在客户端上调用静态方法.
举一个我所说的例子,你可以查看我的github项目代码解释自己. https://github.com/mr-antivirus/riur
希望有所帮助!
[编辑]这是代码!
Client.js
'use strict' import React from 'react'; import { render } from 'react-dom'; import { Provider } from 'react-redux'; import { Router,browserHistory } from 'react-router'; import createStore from '../shared/store/createStore'; import routes from '../shared/routes'; const store = createStore(window.__app_data); const history = browserHistory; render ( <Provider store={store}> <Router history={history} routes={routes} /> </Provider>,document.getElementById('content') )
Server.js
app.use((req,res,next) => { match({ routes,location:req.url },(err,renderProps) => { if (err) { return res.status(500).send(err); } if (redirectLocation) { return res.redirect(302,redirectLocation.pathname + redirectLocation.search); } if (!renderProps) { return next(); } // Create the redux store. const store = createStore(); // Retrieve the promises from React Router components that have a fetchData method. // We use this data to populate our store for server side rendering. const fetchedData = renderProps.components .filter(component => component.fetchData) .map(component => component.fetchData(store,renderProps.params)); // Wait until ALL promises are successful before rendering. Promise.all(fetchedData) .then(() => { const asset = { javascript: { main: '/js/bundle.js' } }; const appContent = renderToString( <Provider store={store}> <RouterContext {...renderProps} /> </Provider> ) const isProd = process.env.NODE_ENV !== 'production' ? false : true; res.send('<!doctype html>' + renderToStaticMarkup(<Html assets={asset} content={appContent} store={store} isProd={isProd} />)); }) .catch((err) => { // TODO: Perform better error logging. console.log(err); }); }); });
RedditContainer.js
class Reddit extends Component { // Used by the server,ONLY,to fetch data static fetchData(store) { const { selectedSubreddit } = store.getState(); return store.dispatch(fetchPosts(selectedSubreddit)); } // This will be called once on the client componentDidMount() { const { dispatch,selectedSubreddit } = this.props; dispatch(fetchPostsIfNeeded(selectedSubreddit)); } ... Other methods };
HTML.js
'use strict'; import React,{ Component,PropTypes } from 'react'; import ReactDom from 'react-dom'; import Helmet from 'react-helmet'; import serialize from 'serialize-javascript'; export default class Layout extends Component { static propTypes = { assets: PropTypes.object,content: PropTypes.string,store: PropTypes.object,isProd: PropTypes.bool } render () { const { assets,content,store,isProd } = this.props; const head = Helmet.rewind(); const attrs = head.htmlAttributes.toComponent(); return ( <html {...attrs}> <head> {head.base.toComponent()} {head.title.toComponent()} {head.Meta.toComponent()} {head.link.toComponent()} {head.script.toComponent()} <link rel='shortcut icon' href='/favicon.ico' /> <Meta name='viewport' content='width=device-width,initial-scale=1' /> </head> <body> <div id='content' dangerouslySetInnerHTML={{__html: content}} /> <script dangerouslySetInnerHTML={{__html: `window.__app_data=${serialize(store.getState())}; window.__isProduction=${isProd}`}} charSet='utf-8' /> <script src={assets.javascript.main} charSet='utf-8' /> </body> </html> ); } };
重申……
>在客户端上,获取状态变量并将其传递给您的商店.>在服务器上,遍历组件,调用fetchData并传递商店.等待承诺得到解决,然后渲染.>在HTML.js(您的renderView函数)中,序列化您的Redux存储并将输出呈现为客户端的javascript变量.>在React组件中,仅为要调用的服务器创建静态fetchData方法.发送您需要的操作.