facebook / react

The library for web and native user interfaces.
https://react.dev
MIT License
229.08k stars 46.86k forks source link

Extending react-dom #6033

Closed jide closed 8 years ago

jide commented 8 years ago

I would like to create a renderer that extends react-dom, that is overrides some parts of it.

The goal is to be able to keep react-dom but swap out some parts of it, ultimately ReactCompositeComponent and ReactDOMComponent.

Since in 0.14 react-dom is buried inside react itself, I created a script that downloads some react-dom files, and created a jscodeshift transform that rewrites imports from var ReactCurrentOwner = require(ReactCurrentOwner');to var ReactCurrentOwner = require('react/lib/ReactCurrentOwner');, and to files i'd like to customize var ReactMount = require('./ReactMount'); (how fun is that ? :) ).

It seems react 0.15 will bring significant changes regarding react-dom and react separation, but for now we have to work around this.

So I end up with custom ReactDOM, ReactMount, ReactDefaultInjection, instantiateReactComponent, ReactChildReconciler and ReactMultiChild.

But when i try to render something with my custom ReactDOM.render, I get this error :

Uncaught Invariant Violation: EventPluginRegistry: Cannot inject event plugin ordering more than once. You are likely trying to load more than one copy of React.

Since the injection is called once with my custom injection, how is that possible ? Am I missing something here ? I suspect some global tying things somehow but can't figure it.

I created a repo with this little experiment here : https://github.com/jide/react-dom-custom

iamdustan commented 8 years ago

Potentially try requiring react/lib/ReactIsomorphic as your react entrypoint. The main react lib still has ReactDOM in it (therefore likely calling its own DefaultInjection).

Typical caveat: we’re playing with non-public APIs that can break at any time. 😁

jide commented 8 years ago

Not sure I understand here, you mean requiring react like this in the app ?

import React, { Component, PropTypes } from 'react/lib/ReactIsomorphic';

I get a different error when I do this :

Warning: React can't find the root component node for data-reactid value `.0`. If you're seeing this message, it probably means that you've loaded two copies of React on the page. At this time, only a single copy of React can be loaded at a time.

...but I must say I absolutely don't understand why, if react points to react/lib/ReactIsomorphic ? And how I could prevent react from using react-dom here and there ?

Thank you for helping !

Yeah I know these are private APIs and it's bad ;)

jide commented 8 years ago

Aren't ReactDOM.js and ReactDOMServer.js the only files calling ReactDefaultInjection.inject(); ?

jide commented 8 years ago

Okay I got it, React.js imports then assigns itself ReactDOM methods.

So I'm here now, with that error about root component node.

iamdustan commented 8 years ago

I'm on my phone so can't dig in any more myself, but the things I would start with:

  1. Ensure all require (react) funnels to ReactIsomorphic
  2. Debug starting at that error message and work your way backwards to ensure you're not missing any required internal properties in your custom renderer
jide commented 8 years ago

I tried to tweak webpack conf to resolve require differently instead and it seems to be a good way. I'll post my findings when I go further.

And thank you for pointing me at the right solution !

jimfb commented 8 years ago

Since this is a discussion topic, and not a bug in the React core, http://discuss.reactjs.org would be a more appropriate place for this discussion. Other alternatives include reactiflux or IRC. Regardless, this is not a bug in the core, so I'm going to close out the issue. Feel free to continue the discussion on this thread, or move it to another medium.

jide commented 8 years ago

My reasoning was that the issue was related with how to implement custom renderers, but I get the point !