React Context not working with server side rendering
Asked Answered
K

2

8

I'm trying to get react context working with SSR. This is what I have

// server/index.s

import express from "express";
import serverRenderer from "./middleware/renderer";
const PORT = 3000;
const path = require("path");
const app = express();
const router = express.Router();
router.use("^/$", serverRenderer);

app.use(router);
app.listen(PORT, error => {
  console.log("listening on 3000 from the server");
  if (error) {
    console.log(error);
  }
});

This is what the renderer looks like-

export default (req, res, next) => {
  const filePath = path.resolve(__dirname, "..", "..", "..", "index.html");
  fs.readFile(filePath, "utf8", (err, htmlData) => {
    if (err) {
      console.log("err", err);
      return res.status(404).end();
    }
    const store = configureStore();
    store.dispatch(getDesktopFooter(`${req.url}`)).then(data => {
      const preloadedState = store.getState();
      const TestContext = React.createContext({
        hello: "hello"
      });
      const renderedBody = ReactDOMServer.renderToStaticMarkup(
        <TestContext.Provider value={{ hello: "hello" }}>
          <DummyApp />
        </TestContext.Provider>
      );

      // const renderedBody = "";
      //render the app as a string
      const helmet = Helmet.renderStatic();

      //inject the rendered app into our html and send it
      // Form the final HTML response
      const html = prepHTML(htmlData, {
        html: helmet.htmlAttributes.toString(),
        head:
          helmet.title.toString() +
          helmet.meta.toString() +
          helmet.link.toString(),
        body: renderedBody,
        preloadedState: preloadedState
      });

      // Up, up, and away...
      return res.send(html);
    });
  });
};

My DummyApp looks like

import React from "react";
import Test from "./Test";
import { default as AppStyles } from "./App.css";
export default class DummyApp extends React.Component {
  render() {
    console.log("DUMMY APP CONTEXT");
    console.log(this.context);
    return (
      <React.Fragment>
        <div className={AppStyles.base}>
          <Test />
        </div>
      </React.Fragment>
    );
  }
}

The context is always {}, when it should be {hello: "hello"}

Why is this happening?

Kohl answered 14/3, 2019 at 8:43 Comment(3)
You don't seem to have a context Consumer in your DummyApp.Thirza
But the docs say I don't need one?reactjs.org/docs/context.html#dynamic-contextKohl
That example you linked is setting the contextType of the component, which you are not doing either.Thirza
T
4

You need to consume the context in your component for it to be able to read it.

You also need to create the TestContext outside of the server render function so that your component can import it and consume it.

Example

// TestContext.js
export default TestContext = React.createContext({
  hello: "hello"
});

// server.js
const TestContext = require("./TestContext.js")

export default (req, res, next) => {
  // ...
  const renderedBody = ReactDOMServer.renderToStaticMarkup(
    <TestContext.Provider value={{ hello: "hello" }}>
      <DummyApp />
    </TestContext.Provider>
  );
  // ...
};

// DummyApp.js
import TestContext from "./TestContext.js";

export default class DummyApp extends React.Component {
  static contextType = TestContext;

  render() {
    console.log(this.context);
    return (
      <React.Fragment>
        <div className={AppStyles.base}>
          <Test />
        </div>
      </React.Fragment>
    );
  }
}
Thirza answered 14/3, 2019 at 9:56 Comment(0)
K
1

So @Tholle was technically correct, but there was another issue that was the real problem. There wasn't much out there on this, so if someone faces the same problem, I hope they read this answer.

contextType only works for when the react version is >= 16.6.0.

This isn't mentioned in the react docs - https://reactjs.org/docs/context.html#classcontexttype, but weirdly is mentioned here

https://scotch.io/bar-talk/whats-new-in-react-166

Kohl answered 16/3, 2019 at 6:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.