代码之家  ›  专栏  ›  技术社区  ›  Naftali

让SSR使用React Context API

  •  1
  • Naftali  · 技术社区  · 8 年前

    基本上,我们有一个模块,它在服务器端render上读取客户端数据,并将它找到的数据提供给rendertorString(客户端使用 window.__SOME_DATA__

    我们的目标是:

    const contentService = new ServerService();
    const app = (
      <StaticRouter context={context} location={req.url}>
        <App/>
      </StaticRouter>
    );
    
    try {
      await contentService.getSomeData(app);
    } catch (error) {
      console.log('THERE WAS A MARKUP ERROR', error);
    }
    
    const markup = renderToString(
      contentService.withProvider(
        app
      )
    );
    

    服务器服务如下所示:

    export class ServerService {
      items = {};
    
      getSomeData = async (app) => {
        // gets some server side data and saves it to the `items` object
      };
    
      withProvider = (app) => {
        const providedApp = (
          <ServerProvider data={this.items}>
            { app }
          </ServerProvider>
        );
    
        console.log('ITEMS provided', { data: this.items });
    
        return providedApp;
      };
    
      getScriptData() {
        return `
          <script>
              window. __SOME_DATA__ = ${JSON.stringify(this.items)};
          </script>
        `;
      }
    }
    

    最后,但并非最不重要的是我的供应商:

    import * as React from 'react';
    
    const ServerContext = React.createContext(null);
    
    export class ServerProvider extends React.Component {
      render () {
        console.log('Providing data', { props: this.props });
    
        return (
          <ServerContext.Provider value={{ ...this.props.data }}>
            {this.props.children}
          </ServerContext.Provider>
        );
      }
    }
    export const ServerConsumer = ServerContext.Consumer;
    

    问题是它似乎在 withProvider ServerConsumer 组件,它似乎包含 没有什么 --但它 包含传递给提供程序的数据!

    16.4.1


    评论后更新,以下是我如何使用消费者:

    import * as React from 'react';
    import { ServerConsumer } from "./serverContext";
    import { ContentStateProvider } from "./ContentStateProvider";
    
    const renderChildrenWithServerData = (props) => (state, ...rest) => {
      console.log({ state, props, rest }, 'I AM DATA', ServerConsumer);
    
      return (
        <ContentStateProvider currentState={state} {...props} />
      );
    };
    
    export class ContentProvider extends React.Component {
      render() {
        // console.log({ Consumer }, 'CONTEXT is cool');
        return (
          <ServerConsumer>{renderChildrenWithServerData(this.props)}</ServerConsumer>
        );
      }
    }
    
    1 回复  |  直到 8 年前
        1
  •  -1
  •   simbathesailor    8 年前

    在这里提到它是因为,很难把所有代码都写在注释中

    <ServerConsumer>{(value) => { console.log(value)}}</ServerConsumer>
    

    您的消费者版本是:

    <ServerConsumer>
      {renderChildrenWithServerData(this.props)}
    </ServerConsumer>
    

    呈现服务器数据(这个。道具)返回无状态组件。您需要在下面提到的级别检索上下文数据,以便将其传递给renderChildrenWithServerData

    <ServerConsumer>
       {(value) => {
         return renderChildrenWithServerData(value, this.props)
       }}
    </ServerConsumer>
    
    推荐文章