2016-07-18 28 views
2

我有一個使用Redux和React路由器的通用React應用程序。我的一些路由包含的參數,在客戶端,將觸發一個AJAX請求來保存數據以供顯示。在服務器上,這些請求可以同步完成,並在第一個請求上呈現。如何使用React + Redux保護服務器端參數

我遇到的問題是這樣的:在路由組件上調用任何生命週期方法(例如componentWillMount)時,發送將反映在第一個呈現中的Redux操作已經太晚了。

這裏是我的服務器端呈現代碼的簡化視圖:

routes.js

export default getRoutes (store) { 
    return (
    <Route path='/' component={App}> 
     <Route path='foo' component={FooLayout}> 
     <Route path='view/:id' component={FooViewContainer} /> 
     </Route> 
    </Route> 
) 
} 

server.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組分是在服務器上構建,其第一個渲染的道具已經是fi了固定的。我第一次致電render()時,我發送給商店的任何行爲都不會反映出來,這意味着它們不會反映在頁面請求上的內容中。

React Router傳遞的id參數本身並不適用於第一次渲染。我需要同步保存這個值到一個適當的對象。我應該在哪裏補水?

一種解決方案是將其內聯放入render()方法中,以用於在服務器上調用的實例。這對我來說顯然是不正確的,因爲1)它在語義上毫無意義,2)它收集的任何數據都不會被正確地分派到商店。

我見過的另一個解決方案是爲Router鏈中的每個容器組件添加一個靜態的fetchData方法。例如是這樣的:

FooViewContainer.js

class FooViewContainer extends React.Component { 

    static fetchData (query, params, store, history) { 
    store.dispatch(hydrateFoo(loadFooByIdSync(params.id))) 
    } 

    ... 

} 

server.js

let { query, params } = renderProps 
renderProps.components.forEach(comp => 
    if (comp.WrappedComponent && comp.WrappedComponent.fetchData) { 
    comp.WrappedComponent.fetchData(query, params, store, history) 
    } 
}) 

我覺得一定有比這更好的辦法。它不僅看起來相當不雅(.WrappedComponent是一個可靠的界面?),但它也不適用於更高階的組件。如果任何路由組件類被除connect()之外的任何東西包裝,則此操作將停止工作。

我在這裏錯過了什麼?

回答

0

似乎沒有比我原來的問題中包含的fetchData方法更符合慣用的方法。雖然它似乎仍然不雅對我來說,它具有較少的問題比我最初意識到:

  • .WrappedComponent是一個穩定的接口,但無論如何不需要參考。 Redux connect函數自動將原始類中的靜態方法提升爲其包裝器。
  • 任何其他更高級的組件包裝Redux綁定容器需要提升(或通過)任何靜態方法。

有可能是我沒有看到其他方面的考慮,但我已經在我的server.js文件上這樣一個輔助方法解決:

function prefetchComponentData (renderProps, store) { 
    let { params, components, location } = renderProps 
    components.forEach(componentClass => { 
    if (componentClass && typeof componentClass.prefetchData === 'function') { 
     componentClass.prefetchData({ store, params, location }) 
    } 
    }) 
} 
相關問題