【问题标题】:Getting SSR to work with the React Context API让 SSR 与 React Context API 一起工作
【发布时间】:2018-12-31 06:59:00
【问题描述】:

基本上我们有一个模块可以读取服务器端渲染上的客户端数据,并且应该使用它找到的数据将数据提供给 renderToString(客户端使用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 组件时,它似乎包含 nothing -- 但它 应该包含传递给提供者的数据!

当我在客户端需要它时,上下文 api 可以很好地工作,但在服务器端对我来说似乎失败了。

这是使用 react/react-dom 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>
    );
  }
}

【问题讨论】:

  • 你能在 ServerConsumer 中获得什么价值。还有一件事你能告诉你如何在各自的文件中导入 ServerConsumer
  • @stack26 为您更新了 OP。我在消费者中没有得到任何数据。
  • 查看我创建此问题后创建的相关反应 github 问题:github.com/facebook/react/issues/13251
  • 有趣的逻辑。您是否也有完整的客户端代码片段? “并且客户端使用窗口呈现.__SOME_DATA__,但我不想在快速路由上使用全局”是什么意思
  • 您是否设法让它工作@NaftaliakaNeal。我在我的 SSR 应用程序中面临同样的问题。上下文在服务器端很好,但在客户端,它采用默认值(null 或我们设置的任何其他默认值)。

标签: reactjs server-side-rendering react-context


【解决方案1】:

在这里提到它是因为,很难在 cmets 中编写所有代码 以这种方式访问​​作为通过上下文传递的值

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

您的消费者版本是:

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

renderChildrenWithServerData(this.props) 返回一个无状态组件。您需要在下面提到的级别检索上下文数据以将其传递给 renderChildrenWithServerData

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

【讨论】:

  • renderChildrenWithServerData 返回一个消耗数据的函数。
  • 我的错!!我错过了。但是您访问上下文值的方式看起来不正确。让我编辑答案
  • oook 让我知道 :-)
  • 你没有改变任何东西......我目前使用消费者的方式是正确的,因为renderChildrenWithServerData返回了一个利用消费者数据的函数
  • 您在哪里获取上下文数据。我无法理解。对不起。你能告诉我吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 2016-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多