我正在使用Redux和React-router制作一个简单的Mail应用程序.由于我是Redux的新手,我不太了解Redux + Router中的实际数据流.
在页面启动(/
)之后,MailListComponent从服务器获取消息数组.此时不显示MessageComponent,因为它没有单个消息来为其获取数据.
之后state.messages:[]
被取出,应用程序被导航到的所述第一消息state.messages:[]
(/messages/1
)`.
转换完成后,将显示MessageComponent并获取id = 1 info的消息,并且它在单独的请求中是附件.
这是组件模型:
// 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
是作为请求dispacted /messages
结束.
现在:
可以loadMessages()
在MailListComponent的 componentDidMount中调度吗?
如何过渡到/messages/1
正确的?
我应该activeMessageId
在我的州创建吗?
所有这些组件应如何与React-Router连接?
这是我目前的尝试:
export default (store) => { const loadAuth = (nextState, replaceState, next) => { ... }; return (// <== THIS IS A DUMMY COMPONENT. It diplays pre-loader until the app is transitioned to real first message ); };
你能给我一些观点,如何连接点?什么是poper异步数据流逻辑?
我正在使用isomorphic-redux示例作为我的应用程序的基础.虽然是同构的,但正常的Redux app之间不应该有太大的区别
谢谢.
其中一个想法 - 设置onEnter挂钩
,将获取消息,设置为状态和初始化转换.是redux +路由器的方式吗?
但是,这种方式也可能相当棘手,因为/messages
只适用于经过身份验证的用户(其中store.getState().auth.get('loaded') == true
)
在我看来,服务器端渲染很重要.没有它,您将提供只在客户端生活的空白页面.它会严重影响你的SEO.因此,如果我们认为服务器端呈现很重要,我们需要一种方法来获取适合服务器端呈现的数据.
望着的文档服务器端渲染ICW反应路由器,这里是我们发现:
首先我们打电话match
,传递当前位置和我们的路线
然后我们打电话ReactDOMServer.render
,传递它renderProps
我们得到的match
很明显,在进入渲染阶段之前,我们需要访问所获取的数据.
这意味着我们不能使用组件生命周期.我们也不能使用onEnter
或任何其他仅在渲染已经开始时触发的钩子.在服务器端,我们需要在渲染开始之前获取数据.这意味着我们需要能够确定什么,从获取renderProps
我们从得到match
.
常见的解决方案是fetchData
在顶层组件上放置一个静态函数.在你的情况下,它可能看起来像这样:
export default class MailListComponent extends React.Component { static fetchData = (store, props) => { return store.dispatch(loadMessages()); }; // .... }
我们可以fetchData
在服务器端找到这个函数,并在继续渲染之前在那里调用它,因为match
它给了我们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
.在客户端,这将只显示一些loading
屏幕,直到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('\n' + ReactDOM.renderToString() ); res.end(); })
你去吧 我们将完全填充的页面发送给客户端.在那里,我们可以使用onEnter
或生命周期钩子或任何其他方便的方法来获取用户导航客户端时所需的后续数据.但是我们应该尝试确保我们在组件本身上有一个函数或注释(初始操作?),这样我们就可以预先获取服务器端渲染的数据.