2016-07-18 5 views
2

Redux 및 React Router를 사용하는 범용 React 앱이 있습니다. 내 경로 중 일부는 클라이언트에서 AJAX 요청을 트리거하여 데이터를 표시하도록하는 매개 변수를 포함합니다. 서버에서 이러한 요청은 동 기적으로 충족 될 수 있으며 첫 번째 요청에서 렌더링됩니다.React + Redux를 사용하여 서버 측 매개 변수를 hydrate하는 방법

내가 겪고있는 문제는 다음과 같습니다. 라우팅 된 구성 요소에 모든 라이프 사이클 메소드 (예 : componentWillMount)가 호출 될 때까지는 첫 번째 렌더링에 반영 될 Redux 작업을 전달하기에는 너무 늦습니다. FooViewContainer 성분이면

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} />)) 
    } 
}) 

: 여기

단순화 내 서버 측 렌더링 코드의 도면 서버에 구축 된 첫 번째 렌더링을위한 소품은 이미 fi가 될 것입니다 xed. 상점으로 파견하는 모든 조치는 render()에 대한 첫 번째 호출에 반영되지 않습니다. 이는 페이지 요청시 제공되는 내용에 반영되지 않음을 의미합니다.

React Router가 전달하는 id 매개 변수는 그 자체로는 첫 번째 렌더링에 유용하지 않습니다. 그 값을 적절한 물체에 동 기적으로 수화시켜야합니다. 이 수분을 어디에 두어야합니까?

하나의 솔루션은 서버에서 호출되는 인스턴스의 경우 render() 메서드 내부에 인라인으로 배치하는 것입니다. 이것은 분명히 나에게 틀린 것처럼 보입니다. 왜냐하면 1) 의미 론적으로 의미가 없기 때문이며, 2) 수집 한 데이터가 상점에 제대로 전달되지 않기 때문입니다.

내가 본 다른 해결책은 라우터 체인의 각 컨테이너 구성 요소에 정적 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 }) 
    } 
    }) 
} 
1

나는 최근에이 요구 사항의 주위에 기사를 썼습니다 만, redux-sagas를 사용해야합니다. 그것은 redux-thunks의 관점에서 픽업을하고 정적 fetchData/need 패턴을 사용합니다.

https://medium.com/@navgarcha7891/react-server-side-rendering-with-simple-redux-store-hydration-9f77ab66900a

나는이 사가 접근 방식에 대한 추론하기 위하여 훨씬 더 간단하고 명료 한 생각하지만 그건 그냥 내 생각 :

수 있습니다