Search code examples
reactjsreact-nativereactjs-native

How to add functions to ReactElement


I'm trying to use an internal Javascript library which is normally used for the web and which contains millions of lines of code (hence why I would really like to use it rather than change anything in it :D) with React Native.

This library has some DOM manipulations in it which are abstracted, and I'm trying to make the abstraction work using React Native.

Basically, what we do on the web is that we pass an HTML element to the library, and the library fills it with other elements. Later on, this library may remove elements from the tree or add some, depending on what we're telling it to do. So I'd like to be able to pass this library a ReactElement, so that React Native handles the drawing part automatically.

Here is what the library does, very very simplified:

function libraryCode(element) {
    element.append(otherElement);
}
var element = document.createElementNS('div');
libraryCode(element);
return element;

And here is what I'd like to be able to do:

render() {
    var element = React.createElement(Element);
    libraryCode(element);
    return element;
}

But ReactElement doesn't have an append function. So I was wondering if there was a way to add functions to ReactElement someway. It would allow me to create a function called append that would add the child and re-render the element. I've tried and it's readonly obviously. I wanted to extend the ReactElement class but how to tell React to use my class instead of ReactElement?

var elem = React.createElement(Element);
elem.append = function() {};

I'm also open to new ideas, I'm quite new to React/React Native so maybe I'm going all wrong with this! :)

Thanks


Solution

  • What you need to do is use React.cloneElement and then do your appending by passing in children. This should allow you to do:

    function libraryCode(element, otherElement) {
      return React.cloneElement(element, null, [otherElement]);
    }
    

    EDIT

    The closest I got to getting it to work but not conform to your needs is this:

    var oldCreateElement = React.createElement;
    React.createElement = function(...args) {
      let element = Object.assign({}, oldCreateElement(...args));
      element.append = (otherElement) => {
        // Unfortunately you simply can't replace the
        // reference of `element` by the result of this operation
        return React.cloneElement(element, null, [
          React.cloneElement(otherElement, {
            // You must give a `key` or React will give you a warning
            key: Math.random(),
          }),
        ]);
      };
      return element;
    };
    

    This will only let you do:

    var element = React.createElement(Element);
    element = element.append(<Text>Hi</Text>);
    return element;
    

    But not:

    var element = React.createElement(Element);
    element.append(<Text>Hi</Text>);
    return element;
    

    Anyway, this is very hacky and NOT recommended and frowned upon because it requires monkey-patching.