Redux と React Router を使用するユニバーサル React アプリがあります。私のルートの一部には、クライアント上で AJAX リクエストをトリガーして表示用のデータをハイドレートするパラメーターが含まれています。サーバーでは、これらのリクエストを同期的に処理し、最初のリクエストでレンダリングできます。
私が直面している問題は次のとおりです。componentWillMount
ルーティングされたコンポーネントでライフサイクル メソッド (例: ) が呼び出されるまでに、最初のレンダリングに反映される Redux アクションをディスパッチするには遅すぎます。
これは、サーバー側のレンダリング コードの簡略図です。
ルート.js
export default getRoutes (store) {
return (
<Route path='/' component={App}>
<Route path='foo' component={FooLayout}>
<Route path='view/:id' component={FooViewContainer} />
</Route>
</Route>
)
}
サーバー.js
let store = configureStore()
let routes = getRoutes()
let history = createMemoryHistory(req.path)
let location = req.originalUrl
match({ history, routes, location }, (err, redirectLocation, renderProps) => {
if (redirectLocation) {
// redirect
} else if (err) {
// 500
} else if (!renderProps) {
// 404
} else {
let bodyMarkup = ReactDOMServer.renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>)
res.status(200).send('<!DOCTYPE html>' +
ReactDOMServer.renderToStaticMarkup(<Html body={bodyMarkup} />))
}
})
コンポーネントがサーバー上にFooViewContainer
構築されると、最初のレンダリングの小道具はすでに修正されています。ストアにディスパッチするアクションは、 への最初の呼び出しにはrender()
反映されません。つまり、ページ リクエストで配信されるものには反映されません。
id
React Router が渡すパラメーターは、それ自体では最初のレンダリングには役立ちません。その値を適切なオブジェクトに同期的にハイドレートする必要があります。この水分補給はどこに置けばいいですか?
render()
1 つの解決策は、サーバー上で呼び出される場合に、メソッド内にインラインで配置することです。1) 意味的に意味がなく、2) 収集したデータがストアに適切にディスパッチされないため、これは明らかに間違っているように思えます。
私が見た別の解決策fetchData
は、Router チェーンの各コンテナ コンポーネントに静的メソッドを追加することです。たとえば、次のようなものです。
FooViewContainer.js
class FooViewContainer extends React.Component {
static fetchData (query, params, store, history) {
store.dispatch(hydrateFoo(loadFooByIdSync(params.id)))
}
...
}
サーバー.js
let { query, params } = renderProps
renderProps.components.forEach(comp =>
if (comp.WrappedComponent && comp.WrappedComponent.fetchData) {
comp.WrappedComponent.fetchData(query, params, store, history)
}
})
これよりも良いアプローチがあるに違いないと感じています。それはかなり洗練されていないように見えるだけでなく (.WrappedComponent
信頼できるインターフェイスですか?)、高次のコンポーネントでは動作しません。ルーティングされたコンポーネント クラスのいずれかがこれ以外のものによってラップされている場合connect()
、動作が停止します。
ここで何が欠けていますか?