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

React Context not available in components #52

Closed
MrAvantiC opened this issue Aug 10, 2019 · 15 comments
Closed

React Context not available in components #52

MrAvantiC opened this issue Aug 10, 2019 · 15 comments
Assignees

Comments

@MrAvantiC
Copy link

Hey Dennis!
Sorry for this neverending story, but I have another problem using the jsx/webpack adapter. :/

Describe the bug
We have a use case where we need data available to every component. To avoid "prop drilling" we want to make use of the Context-API for this.

I tried to make use of the react-server-render and react-client-render for this to make the context available to every component/variant in UIEngine.
This looked good at first, since the Context-Provider showed up in the component tree:
Bildschirmfoto 2019-08-10 um 15 42 59

Unfortunately, the actual context is not accessible in the components of the UIEngine. It appears like the context is not passed through to all the underlying components.

To Reproduce
Steps to reproduce the behavior:

  1. A minimal example of the problem can be found here: https://github.com/MrAvantiC/uiengine-context
  2. Install dependencies and start development server
  3. See the console-ouput of the render() method in <Footer />

Expected behavior
The context should be available in the <Footer /> component.
I can confirm that the same code works in CRA/Next.js.

Kind regards,
René

@dennisreimann
Copy link
Owner

Without having had a deeper look into this: Did you try and compare the React Sample Project? It does not utilize the Webpack adapter, but also uses the Context API https://github.com/dennisreimann/uiengine-sample-react/blob/master/lib/uiengine/react.js

@MrAvantiC
Copy link
Author

Well, as far as I can tell, the Webpack adapter doesn't offer a similar hook like wrapElementBeforeRender, does it?
I tried to imitate that functionality by utilizing the renderers like that:

// react-server-render.js

module.exports = function serverRender(Component, props) {
  return renderToString(
    <ThemeProvider>
      <Component {...props} />
    </ThemeProvider>
  )
}

Not sure if that's the best way but it did insert the ThemeProvider into the component tree atleast. Just accessing its provided context doesn't work.

@dennisreimann
Copy link
Owner

Yep, I have tried several ways now, but I also can't get the ThemeProvider to update when it is passed the value prop. I am not really familiar with the React Context API, but from what I saw in the docs it should be working :(

@MrAvantiC
Copy link
Author

Damn!

but I also can't get the ThemeProvider to update when it is passed the value prop

Does that mean you were able to access the this.context in the Class Component but it (just) didn't update?
Because in my tests this.context wasn't even defined (probably not passed through by the webpack build process?) in the Component.

@dennisreimann
Copy link
Owner

It is defined when you initialize it with React.createContext(‚initial value‘), but that does not help.

Had another look earlier today and my guess is that it boils down to the same problem as mentioned in #46, namely that somehow stuff specified in the render files is not accessible in the variants, because they are two separate files and not bundled together.

You can see this when you are using the latest versions (2.4.x) and have a look at how they are build (dist/_webpack) and integrated in the HTML.

Don‘t know for sure, but that‘s what came to my mind as the most likely thing to cause this.

@MrAvantiC
Copy link
Author

namely that somehow stuff specified in the render files is not accessible in the variants

I don't quite understand this point.
After all, the variants do require the actual components ...shouldn't that be resolved by webpack?


Unfortunately, my webpack knowledge is kinda limited.
Do you see any possible solution to this - like packaging them together somehow?

@dennisreimann
Copy link
Owner

dennisreimann commented Aug 13, 2019

After all, the variants do require the actual components ...shouldn't that be resolved by webpack?

That's correct. Nevertheless, currently the variants and render functions (serverRender and clientRender) live in separate bundles.

See the source of this example for instance:

<script src="/_webpack/jsx-client.js"></script>
<script src="/_webpack/src_elements_label_variants_label_jsx-client.js"></script>
<script>
        window.UIengineWebpack_render(
          window.UIengineWebpack_component,
          {"id":"name","title":"Name"}
        )
</script>

This is the generated output:

  • jsx-client.js provides the render function UIengineWebpack_render
  • VARIANT_jsx-client.js provides the variant/component as export UIengineWebpack_component

They aren't bundled together and from what I have seen so far, this is the problem with the React hooks and context APIs. They seem to rely on side effects that require both files to share the same scope (and by that the exact same React instance).

I'll tinker more with that when I find the time to do so :)

@dennisreimann dennisreimann self-assigned this Aug 13, 2019
@MrAvantiC
Copy link
Author

No worries, we'll figure out a way that works for our use case. :)
Appreciate your commitment!

@dennisreimann
Copy link
Owner

I got it kinda working – at least on the client-side. Same problem still when rendering server-side, which I don't understand yet as the React instances there are the same too.

However, as I am still unsatisfied with the approach I'm taking to make this work and I am still trying to find a better way, here is something I can imagine to work for you in the meantime: Use the Webpack externals option to extract React and ReactDOM from the bundle:

externals: {
  react: 'React',
  'react-dom' : 'ReactDOM',
}

You would then have to provide them via CDN or local linking in the preview uiengine.html template.

@MrAvantiC
Copy link
Author

Hey Dennis,
I tried excluding them from the build (which worked) and included them via CDN:
https://github.com/MrAvantiC/uiengine-context/commit/29457cf429a07137c78b4d764f93ef48e95c8d77

Unfortunately, accessing this.context in the Component still returns undefined.
Am I missing something?

@dennisreimann
Copy link
Owner

Ok, took another look and I really don't know enough about how this is supposed to work to fix it.
I'd appreciate someone having a deeper look and assisting me with debugging that.

From what I saw the problem seems to be that the context cannot be shared across React instances coming from different bundles.

@dennisreimann
Copy link
Owner

Status update: I got it working now :)

Will clean up the code and test whether or not this helps with the hooks issue as well during the next days.

dennisreimann added a commit that referenced this issue Aug 21, 2019
Closes #52.

Signed-off-by: Dennis Reimann <mail@dennisreimann.de>

new

Signed-off-by: Dennis Reimann <mail@dennisreimann.de>

new

Signed-off-by: Dennis Reimann <mail@dennisreimann.de>
@dennisreimann
Copy link
Owner

@dennisreimann
Copy link
Owner

v2.5 is available now and fixes this :)

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

No branches or pull requests

2 participants