akxcv / vuera

:eyes: Vue in React, React in Vue. Seamless integration of the two. :dancers:
MIT License
4.29k stars 239 forks source link

Context API support #50

Open kball opened 5 years ago

kball commented 5 years ago

I'm attempting to utilize Vuera to create Gutenberg components for Wordpress using Vue. Overall I'm pretty happy with it, but I'm running into a limitation that severely restricts the set of things I can do:

Gutenberg utilizes the Context API that was introduced in React 16 extensively throughout its built-in editor components, particularly to manage when a block is "selected" vs not. This context does not appear to bridge across the vuera embed.

The high level structure I'm using returns a VueInReact wrapped component to Gutenberg, with my core Vue component handling my custom logic, and then as necessary embedding ReactInVue wrapped Gutenberg builtins.

So we have React (gutenberg, sets context) -> Vue (my code) ----> React (gutenberg, looks for context and doesn't find it)

I'm happy to try to figure out/implement a fix for this, but would appreciate a pointer in the right direction if you have any ideas.

kball commented 5 years ago

Digging into this a more, I haven't been able to track down how to programatically pull out a list of the Contexts that a component is embedded in.

Ideally I'd like to have the VueInReact wrapper grab that list (it's a normal React component that has access to existing contexts), stash them on the Vue instance, and then teach ReactInVue to look up its parent tree within Vue for contexts and plug them into place again.

Maybe @gaearon or @acdlite could help point us in the right direction?

gziolo commented 5 years ago

I get here from yout post @kball: https://zendev.com/2018/07/31/wordpress-gutenberg-blocks-vue.html 😃

What a nice coincident, I was working on refactoring one of the components mentioned in the article to use new Context API. To do it, I had to apply some updates to the custom serializer we built to make output compatible with WordPress specific rules. Related PR is here: https://github.com/WordPress/gutenberg/pull/8189. It might be helpful for your explorations.

I think that the code that needs to be included in vuera can be found in react-dom here: https://github.com/facebook/react/blob/master/packages/react-dom/src/server/ReactPartialRenderer.js#L938-L978

I might be wrong, not sure if the issue is with rendering, or with react itself.

akxcv commented 5 years ago

Hi, yes, I've been thinking about how to bridge React context across vuera. I think that the best solution is to render inner React components via portals instead of ReactDOM.render (only in React > 16). This should preserve context if I'm not mistaken.

gaearon commented 5 years ago

related https://github.com/facebook/react/issues/13336

haldunanil commented 4 years ago

Any new updates on this? This is a significant limitation of vuera for us right now, where we're passing a theme prop via the Context API to components in our component library all styled using styled-components, but the components fail to render because of their theme dependencies.

akxcv commented 4 years ago

@haldunanil no, unfortunately, there haven't been any updates so far. What you could do in your case, though, is create a set of wrapper components instead of using Vuera as is. It would work something like this:

  1. Get theme from context and pass it down as a prop.
  2. Use Vuera to get from React to Vue.
  3. Get theme prop and assign it onto the Vue instance.
  4. (Do your things in Vue...)
  5. Get theme from the Vue instance and pass it down as a prop.
  6. Use Vuera to get from Vue to React.
  7. Get theme prop and assign it onto context.

I didn't try this at home, but it should be possible to create a sort of a bridge this way. Furthermore, such a bridge can be extended to do more advanced things in the future. It's also not cumbersome at all: if you do things right, all the bridging logic would be hidden behind a couple of components (one for React->Vue bridge, one for Vue->React bridge).

haldunanil commented 4 years ago

@akxcv is there a gist or working codesandbox you can point me to? I think I follow your explanation but am confused how it would work in practice. I'm also not super familiar with Vue so I may be missing some stuff here.

akxcv commented 4 years ago

Sadly, I'm not aware of any gists or sandboxes. I'll try to experiment with this when I have a moment.

haldunanil commented 4 years ago

Appreciate it!

Tofandel commented 4 years ago

React contexts is basically vue's inject/provide so this should be used instead of the suggestion to add props

I can have a look, it should actually be very straightforward to implement this

The wrapped component should invisibly pass the context to the child component by providing it and the Vue to react by injecting it, but the vue component could also use the context by using what's provided

React's api provide no way to retrieve all contexts though, so some React under the hood hack might be needed (which might break if they update the inner workings)

If there is no way to achieve this, the Portal api can be Used but then the Vue component will be completely unaware of context and a separate api will be needed to pass context to it

tujoworker commented 4 years ago

That would be awesome @Tofandel!

Tofandel commented 4 years ago

So as it seems migrating this lib to a portal would be a huge undertaking, it is possible to access the full context using a react internal in v16: this.__reactInternalMemoizedUnmaskedChildContext which solves the only issue to this dev, as previously explained it might needs some checks because this property might be non existent or under another name in other react versions

Untested yet but the dev is on my master fork Will do a PR when tested

akxcv commented 4 years ago

vuera itself is a pretty small library, it should not be very hard to rewrite whatever logic there currently is.

On 6 Jan 2020, at 14:14, Adrien Foulon notifications@github.com wrote:

So as it seems migrating this lib to a portal would be a huge undertaking, it is possible to access the full context using a react internal: this.__reactInternalMemoizedUnmaskedChildContext

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/akxcv/vuera/issues/50?email_source=notifications&email_token=AEDFNYUDVJUFAP3TUHLUY63Q4MOCNA5CNFSM4FM4W3WKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEIFI6JI#issuecomment-571117349, or unsubscribe https://github.com/notifications/unsubscribe-auth/AEDFNYWJIETCCK26HOKGWKDQ4MOCNANCNFSM4FM4W3WA.