我想要得到什么
>页面启动(/)后,MailListComponent从服务器中获取消息数组。此时,MessageComponent不显示,因为它没有单个消息来为其获取数据。
>在state.messages:[]被取出后,app被导航到state.messages的第一条消息:[](/ messages / 1)`。
>转换完成后,将显示MessageComponent并获取id = 1信息的消息,它在另一个请求中是附件。
以下是组件模型:
我在做什么
// MailListActions.js export function loadMessages() { return { type: 'LOAD_MESSAGES',promise: client => client.get('/messages') }; } // MailListReducer.js import Immutable from 'immutable'; const defaultState = { messages: [],fetchingMessages: false }; export default function mailListReducer(state = defaultState,action = {}) { switch (action.type) { case 'LOAD_MESSAGES_REQUEST': return state.merge({fetchingMessages: true}); case 'LOAD_MESSAGES': return state.merge({fetchingMessages: false,messages: action.res.data || null}); case 'LOAD_MESSAGES_FAILURE': // also do something default: return state; } }
当我使用promiseMiddleware时,随着请求/消息的结束,LOAD_MESSAGES,LOAD_MESSAGES_REQUEST和LOAD_MESSAGES_FAILURE将被调度。
现在:
>在MailListComponent的componentDidMount中调度loadMessages()可以吗?
>如何正确地转换到/ messages / 1?
>我应该创建activeMessageId< Integer>在我的状态
>所有这些组件应该如何连接React-Router?
这是我目前的尝试:
export default (store) => { const loadAuth = (nextState,replaceState,next) => { ... }; return ( <Route name="app" component={App} path="/" onEnter={loadAuth}> <IndexRoute component={Content}/> // <== THIS IS A DUMMY COMPONENT. It diplays pre-loader until the app is transitioned to real first message <Route path="messages/:id" component={Message}/> </Route> ); };
你能给我一些点,如何连接点?什么是poper异步数据流逻辑?
我正在使用isomorphic-redux示例作为我的应用程序的基础。虽然是同构的,但在正常的Redux应用程序之间不应该有太大的区别
谢谢。
UPDATE
其中一个想法 – 设置onEnter hook为< IndexRoute component = {Content} />,将获取消息,设置为状态和初始化转换。它是redux路由器的方式吗? 然而,这种方式也可能相当棘手,因为/消息仅适用于经过身份验证的用户(其中store.getState()。auth.get(‘loaded’)== true)
看着the docs for server side rendering i.c.w. react-router,这是我们找到的:
>首先我们称之为匹配,传递当前位置和路线
>然后我们调用ReactDOMServer.render,传递我们从匹配得到的renderProps
很明显,在进入渲染阶段之前,我们需要访问获取的数据。
这意味着我们不能使用组件生命周期。我们也不能使用onEnter或任何其他只在渲染已经开始时才触发的钩子。在服务器端,我们需要在渲染开始之前获取数据。这意味着我们需要能够确定从我们从匹配得到的renderProps中获取的内容。
常见的解决方案是在顶级组件上放置一个静态fetchData函数。在你的情况下,它可能看起来像这样:
export default class MailListComponent extends React.Component { static fetchData = (store,props) => { return store.dispatch(loadMessages()); }; // .... }
我们可以在服务器端找到这个fetchData函数,然后在继续渲染之前调用它,因为匹配给了包含匹配组件类的renderProps。所以我们可以循环使用它们并抓取所有fetchData函数并调用它们。这样的事情
var fetchingComponents = renderProps.components // if you use react-redux,your components will be wrapped,unwrap them .map(component => component.WrappedComponent ? component.WrappedComponent : component) // now grab the fetchData functions from all (unwrapped) components that have it .filter(component => component.fetchData); // Call the fetchData functions and collect the promises they return var fetchPromises = fetchingComponents.map(component => component.fetchData(store,renderProps));
fetchData返回store.dispatch的结果,它将是Promise。
在客户端,这将只显示一些加载屏幕,直到Promise满足,但是在服务器端,我们将需要等到发生这种情况,所以当我们进行渲染阶段时,我们实际上将数据存储在商店中。我们可以使用Promise.all:
// From the components from the matched route,get the fetchData functions Promise.all(fetchPromises) // Promise.all combines all the promises into one .then(() => { // now fetchData() has been run on every component in the route,and the // promises resolved,so we know the redux state is populated res.status(200); res.send('<!DOCTYPE html>\n' + ReactDOM.renderToString( <Html lang="en-US" store={app.store} {...renderProps} script="/assets/bridalapp-ui.js" /> ) ); res.end(); })
你去了我们向客户端发送一个完全填充的页面。在那里,我们可以使用onEnter或生命周期挂钩或任何其他方便的方法来获取用户在客户端导航时所需的后续数据。但是我们应该尝试确保我们在组件本身具有可用的功能或注释(初始操作?),以便我们可以预先为服务器端渲染提取数据。