0

我正在嘗試使用Apollo客戶端,並且遇到一些問題,並將其放入使用redux的反應入門工具包中。 https://github.com/kriasoft/react-starter-kit/tree/feature/redux使用apollo客戶端與反應入門工具包同構時獲取校驗和無效警告

嘗試使用從這裏的技術:http://dev.apollodata.com/react/server-side-rendering.html

但我得到的錯誤

warning.js:36Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server: 
(client) </div></header><div data-reactid="19">Lo 
(server) </div></header><div class="Home-root-2IM 

這是我實現

// server.js 
... 
const component = (
    <App context={context}> 
    <ApolloProvider client={context.client} store={context.store}> 
     {route.component} 
    </ApolloProvider> 
    </App> 
); 


await getDataFromTree(component); 

data.children = ReactDOM.renderToString(component); 
data.style = [...css].join(''); 
data.scripts = [ 
    assets.vendor.js, 
    assets.client.js, 
]; 
data.state = context.store.getState(); 
if (assets[route.chunk]) { 
    data.scripts.push(assets[route.chunk].js); 
} 

const html = ReactDOM.renderToStaticMarkup(<Html {...data} />); 
res.status(route.status || 200); 
res.send(`<!doctype html>${html}`); 
... 

和客戶端

// client.js 
... 
const component = (
    <App context={context}> 
    <ApolloProvider client={context.client} store={context.store}> 
     {route.component} 
    </ApolloProvider> 
    </App> 
); 

appInstance = ReactDOM.render(
component, 
    container, 
() => onRenderComplete(route, location), 
); 
... 


// Home.js 

class Home extends React.Component { 
    static propTypes = { 
    collections: PropTypes.arrayOf(PropTypes.shape({ 
     id: PropTypes.string.isRequired, 
     title: PropTypes.string.isRequired, 
     subtitle: PropTypes.string.isRequired, 
     photo: PropTypes.string, 
    })).isRequired, 
    }; 

    render() { 
    const props = this.props; 
    const { loading, allCollections } = props.data; 

    if (loading) { 
     return <div>Loading</div>; 
    } else { 
     return (
     <div className={s.root}> 
      <div className={s.container}> 
      <h1 className={s.title}>Collections</h1> 
      <ul> 
       {allCollections.map((collection) => 
       <li key={collection.id}> 
        <h3>{collection.title}</h3> 
        <img src={collection.photo} width="200"/> 
       </li> 
      )} 
      </ul> 
      </div> 
     </div> 
    ); 
    } 

    } 
} 

Home.propTypes = { 
    data: PropTypes.shape({ 
    loading: PropTypes.bool.isRequired, 
    allCollections: PropTypes.array, 
    }).isRequired, 
}; 


const HomeWithStyles = withStyles(s)(Home); 
const HomeWithData = graphql(getQuery)(HomeWithStyles); 
export default connect()(HomeWithData); 



// App.js 
import React, { Children, PropTypes } from 'react'; 

const ContextType = { 
    // Enables critical path CSS rendering 
    // https://github.com/kriasoft/isomorphic-style-loader 
    insertCss: PropTypes.func.isRequired, 
    // Integrate Redux 
    // http://redux.js.org/docs/basics/UsageWithReact.html 
    store: PropTypes.shape({ 
    subscribe: PropTypes.func.isRequired, 
    dispatch: PropTypes.func.isRequired, 
    getState: PropTypes.func.isRequired, 
    }).isRequired, 
    client: PropTypes.object.isRequired, 
}; 

/** 
* The top-level React component setting context (global) variables 
* that can be accessed from all the child components. 
* 
* https://facebook.github.io/react/docs/context.html 
* 
* Usage example: 
* 
* const context = { 
*  history: createBrowserHistory(), 
*  store: createStore(), 
* }; 
* 
* ReactDOM.render(
*  <App context={context}> 
*  <Layout> 
*   <LandingPage /> 
*  </Layout> 
*  </App>, 
*  container, 
* ); 
*/ 
class App extends React.PureComponent { 

    static propTypes = { 
    context: PropTypes.shape(ContextType).isRequired, 
    children: PropTypes.element.isRequired, 
    }; 

    static childContextTypes = ContextType; 

    getChildContext() { 
    return this.props.context; 
    } 

    render() { 
    // NOTE: If you need to add or modify header, footer etc. of the app, 
    // please do that inside the Layout component. 
    return Children.only(this.props.children); 
    } 

} 

export default App; 
+0

有你看看[本GH線程(HTTPS:/ /github.com/ReactTraining/react-router/issues/2704)? ''爲我的客戶端做了訣竅。 – vwrobel

+0

事實證明,我必須明確地設置apollo初始狀態客戶端來重新提供與服務器相同的存儲 - 並且導致校驗和錯誤 – MonkeyBonkey

回答

0

所以答案是,初始狀態下沒有爲阿波羅客戶數據

// client.js 

let apolloOptions = { 
    ssrMode: false, 
    initialState: { apollo: { data: window.APP_STATE.apollo.data } }, // NOT __APOLLO_STATE__ as set in some of the examples online 
    ssrForceFetchDelay: 500, 
    networkInterface: createNetworkInterface({ 
    uri: window.APP_STATE.runtime.graphUri, 
    }), 
    opts: { 
    credentials: 'same-origin', 
    }, 
}; 
const client = new ApolloClient(apolloOptions); 

和服務器上

// server.js 

... 
// data.state gets rendered by the server to client as APP_STATE 
data.state = context.store.getState(); 
data.state.apollo = client.store ? client.store.getState().apollo : null; 
... 
相關問題