【问题标题】:Getting checksum invalid warning when using apollo client isomorphically with react starter kit将 apollo 客户端与 React Starter Kit 同构使用时出现校验和无效警告
【发布时间】:2017-05-02 10:06:37
【问题描述】:

我正在尝试使用 Apollo 客户端,但在将其放入带有 redux 的 react 入门套件时遇到了一些问题。 https://github.com/kriasoft/react-starter-kit/tree/feature/redux

尝试使用此处的技术: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;

【问题讨论】:

  • 你看过this gh thread吗? &lt;Router key={Math.random()} history={browserHistory} routes={routes} /&gt; 为我做了客户端。
  • 原来我必须明确设置 apollo 初始状态客户端,以将那里的存储重新水化到与服务器相同的位置——这导致了校验和错误

标签: react-redux isomorphic-javascript react-starter-kit react-apollo


【解决方案1】:

所以答案是没有为 apollo 客户端数据设置初始状态

// 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;
...

【讨论】:

    猜你喜欢
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 2019-03-01
    • 2020-05-29
    • 2019-03-27
    • 2016-10-15
    • 2016-02-04
    • 2015-12-02
    相关资源
    最近更新 更多