Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixing React.createContext in SSR #40

Open
tadeuszwojcik opened this issue Aug 24, 2018 · 18 comments
Open

fixing React.createContext in SSR #40

tadeuszwojcik opened this issue Aug 24, 2018 · 18 comments

Comments

@tadeuszwojcik
Copy link

Hi,
would you consider making changes analogous to apollographql/react-apollo#2304 in order to fix context handling? I'm happy to create pull request for that if you'd like to.
Thanks!

@jaydenseric
Copy link

jaydenseric commented Oct 29, 2018

As another reference, I've recently fixed the graphql-react SSR preload function for React v16.6 context: Diff here.

@ctrlplusb
Copy link
Owner

ctrlplusb commented Oct 29, 2018

@tadeuszwojcik of course, always happy to keep inline with the latest fixes and enhancements that the Apollo team have applied. Would really appreciate the PR. 👍

@jcampalo
Copy link

Any updates on this? I have problems updating to react 16.6.x which makes react-async-bootstrapper unusable.

@isaachinman
Copy link

isaachinman commented Dec 14, 2018

@ctrlplusb Any idea when you'll be releasing this? We're using react-tree-walker over at next-i18next. Thanks!

@jcampalo
Copy link

jcampalo commented Dec 17, 2018

Seems like @ctrlplusb is inactive, it's a bit annoying. Did anyone create a fork and published it on npm?

@oyeanuj
Copy link

oyeanuj commented Dec 29, 2018

@isaachinman @jcampalo Did you guys publish a fork by any chance?

@isaachinman
Copy link

Hi @oyeanuj. Over at next-i18next I had to move away from react-tree-walker entirely due to:

  1. Performance impact.
  2. Unreconcilable issues with context.

It's a bit of a shame, but I think this project is self-aware in that it's not appropriate for every use case.

Good luck!

@oyeanuj
Copy link

oyeanuj commented Dec 29, 2018

@isaachinman what did you end up using instead?

@isaachinman
Copy link

@oyeanuj I took a completely different approach that sidestepped tree traversal entirely. Sorry if that's not helpful.

@jcampalo
Copy link

@ctrlplusb Please give proper rights to others, we need this fix.

@mschipperheyn
Copy link

Shit. completely stuck on this. Days sunk into this already. What are people using as alternatives?

@dan-lee
Copy link
Contributor

dan-lee commented Jan 23, 2019

@mschipperheyn I didn't personally check it myself, but see this: #46 (comment)

@jdwillemse
Copy link

@mschipperheyn I didn't personally check it myself, but see this: #46 (comment)

I tested this and It did not solve this problem.

@jaredLunde
Copy link

Does this fork fix the issue for anyone? It has worked for me. If so I can work on a PR w/ the fix I lifted from react-apollo.

https://github.com/jaredLunde/react-tree-walker

@jaydenseric
Copy link

React hooks is probably a bigger problem than the context API, a lot of libraries including graphql-react and Apollo have given up on walking React trees.

@jaredLunde
Copy link

Yeah, I mean it's a large part of why I haven't even begun looking at Hooks. I need asynchronous components on the server side more than I need hooks. Unfortunately React.lazy + Suspense is useless until their new server renderer is done in the second half of this year so this will have to do.

@jaredLunde
Copy link

jaredLunde commented Feb 12, 2019

Ah, I see what you mean now. Your solution in graphql-react and the new react-apollo getDataFromTree are interesting. I imagine it's a lot more expensive but the reliability is what matters most I guess.

@dan-lee
Copy link
Contributor

dan-lee commented Feb 12, 2019

After the release of React Hooks I've moved away from react-tree-walker.
I figured that it will be an endless fight to keep up with React. Very ambitious to say the least (just thinking about Suspense, Concurrent mode, etc.)

In the end I decided to go the same way as react-apollo did. Even if it's one more complete render cycle. I simplified it a lot for my use case.

If anyone is interested that's how I've roughly done it.
// server.js

// Preparation for SSR
export const PreloadPromiseContext = React.createContext()

// This will called on page load on SSR
const preload = async tree => {
  const loaders = []
  const registerLoader = loaderConfig => loaders.push(loaderConfig)

  // collect
  ReactDOMServer.renderToStaticMarkup(
    <PreloadPromiseContext.Provider value={{ registerLoader }}>
      {tree}
    </PreloadPromiseContext.Provider>
  )

  // resolve one after another
  // loaders will put responses into global store
  for (const { props, loader } of loaders) {
    await loader(props)
  }
}

// Actual SSR
server.use(async (req, res) => {
  const app = (
    <Provider store={store}>
      <App />
    </Provider>
  )

  await preload(app)

  // use state and markup to render the actual HTML output
  const state = store.getState()
  const markup = ReactDOMServer.renderToString(app)
})

Now this is used in combination with a HoC (could maybe be a hook at some point?) Every component which should preload is wrapped with this.

import PreloadPromiseContext from './server.js'

const resolve = loader => Component => {
  class Resolve extends React.Component {
    static contextType = PreloadPromiseContext

    constructor(props, context) {
      super(props, context)

      if (context && typeof window === 'undefined') {
        // fetch on SSR
        context.registerLoader({ props, loader })
      } else {
        // fetch on client side, to make life easier
        // (you might not need this)
        loader(props)
      }
    }

    render() {
      return <Component {...this.props} />
    }
  }

  return hoistNonReactStatics(Resolve, Component)
}

// Example usage for a component. The result will be put in a global store inside the called function
export default presolve(props => props.store.fetchThings())(MyApp)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants