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

Custom Renderer API Support #7850

Closed
iamdustan opened this issue Oct 3, 2016 · 9 comments
Closed

Custom Renderer API Support #7850

iamdustan opened this issue Oct 3, 2016 · 9 comments

Comments

@iamdustan
Copy link
Contributor

I’m working through upgrading some renderers and documentation to the current master build (installing from http://react.zpao.com/builds/master/latest/).

From following along I knew there were some hard breaking changes I wanted to begin a discussion on what commitments React is willing to make at this time to support this use case.

Rather than trying to figure all of the current APIs needed up front I’d like to begin this by looking at the `Mount* entry point and discuss what APIs could be exposed and which should be covered in other APIs.

ReactMount

ReactMount, ReactNativeMount, and ReactTestMount are the entry points to three Facebook/React supported renderers. They all live in this codebase and have first class access to a number of internals that external renderers do not currently get.

Specifically, a few modules that each access are:

(There are a few other modules that I see used between FB and my own renderers beyond these that may be worth future consideration, though these are what I understand to be the most important to unblock renderer development.)

My understanding is that a renderers Mount method is dependent upon the reconciler to bridge the renderer semantics to React core. The reconciler has become effectively private and non-shareable with the recent build changes.

What can be done today to allow renderers to continue existing and experimenting in the 16.x release cycle?

A few initial ideas to get feedback on for possible direction (if any) would be acceptable. With both of these ideas comes developer/console warnings that this is an unsupported and non-guaranteed API that could break at any moment including patch releases:

  • Expose minimal Reconciler surface area
  • Create a ReactReconciler package
@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2016

I think the intention is to move towards Fiber (#6170) which has a completely different API that does not use classes, today’s ReactReconciler, and friends. Fiber reconciler is intentionally written with opaque targets in mind so that it’s decoupled from day one and can be exposed as a package once it’s mature. It doesn’t have all the pitfalls we have today caused by shared state between renderers, like #7386.

In the meantime, if you work on a custom renderer, I think you are encouraged to ship a copy of React reconciler. At least this is what React Native will do as far as I know. This means you aren’t affected by breaking changes in React repo master and can update your renderer at any time. It complicates setting up a custom renderer (you’ll need a script to keep your reconciler fork in sync with React repo) so it would be cool if somebody contributed that for RN and then other renderers could use that. It is not meant to be a long-term solution, but neither is our current renderer architecture.

@iamdustan
Copy link
Contributor Author

Yeah, I’m looking for something to maintain through the 15.4/16 release cycle primarily knowing that Fiber will change the world. It sound like you’re saying you’d rather see a hack from the community to sync the React Reconciler code out of this codebase (something that React Native can avoid by being in this repo) rather than expose something explicitly between the new build format being released and Fiber becoming official and stable?

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2016

It sound like you’re saying you’d rather see a hack from the community to sync the React Reconciler code out of this codebase (something that React Native can avoid by being in this repo)

React Native doesn't plan to avoid it. On the opposite, there is an open diff for React Native to ship a copy of the reconciler that will be manually synced just like I described. This lets RN team experiment with changing the renderer code, and sync it at their own pace.

Exposing the renderer as a package has pitfalls, the most significant one being unintentionally shared state between different renderers, like in #7386.

@iamdustan
Copy link
Contributor Author

Do you have a link to that open diff by chance? I couldn’t find it in my browsing of https://github.com/facebook/react-native/pulls

@gaearon
Copy link
Collaborator

gaearon commented Oct 3, 2016

I don't think it was submitted as a PR, more likely as an internal diff 😞 .
@yungsters Do you have any updates on getting it merged?

@gaearon
Copy link
Collaborator

gaearon commented Oct 27, 2016

I'll close as there are no plans to take extra steps to support custom renderers for stack reconciler while we're changing everything in Fiber. Fiber will have a first-class custom renderer support.

@gaearon gaearon closed this as completed Oct 27, 2016
@sompylasar
Copy link
Contributor

Linking for future readers just for reference:

  • https://twitter.com/dan_abramov/status/801782049963175936
  • prepareForCommit() : void {
    eventsEnabled = ReactBrowserEventEmitter.isEnabled();
    ReactBrowserEventEmitter.setEnabled(false);
    selectionInformation = ReactInputSelection.getSelectionInformation();
    },
    resetAfterCommit() : void {
    ReactInputSelection.restoreSelection(selectionInformation);
    selectionInformation = null;
    ReactBrowserEventEmitter.setEnabled(eventsEnabled);
    eventsEnabled = null;
    },
    createInstance(
    type : string,
    props : Props,
    internalInstanceHandle : Object
    ) : Instance {
    const root = document.documentElement; // HACK
    const domElement : Instance = createElement(type, props, root);
    precacheFiberNode(internalInstanceHandle, domElement);
    return domElement;
    },
    appendInitialChild(parentInstance : Instance, child : Instance | TextInstance) : void {
    parentInstance.appendChild(child);
    },
    finalizeInitialChildren(domElement : Instance, type : string, props : Props) : void {
    const root = document.documentElement; // HACK
    setInitialProperties(domElement, type, props, root);
    },
    prepareUpdate(
    domElement : Instance,
    oldProps : Props,
    newProps : Props
    ) : boolean {
    return true;
    },
    commitUpdate(
    domElement : Instance,
    oldProps : Props,
    newProps : Props,
    internalInstanceHandle : Object
    ) : void {
    var type = domElement.tagName.toLowerCase(); // HACK
    var root = document.documentElement; // HACK
    // Update the internal instance handle so that we know which props are
    // the current ones.
    precacheFiberNode(internalInstanceHandle, domElement);
    updateProperties(domElement, type, oldProps, newProps, root);
    },
    createTextInstance(text : string, internalInstanceHandle : Object) : TextInstance {
    var textNode : TextInstance = document.createTextNode(text);
    precacheFiberNode(internalInstanceHandle, textNode);
    return textNode;
    },
    commitTextUpdate(textInstance : TextInstance, oldText : string, newText : string) : void {
    textInstance.nodeValue = newText;
    },
    appendChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
    parentInstance.appendChild(child);
    },
    insertBefore(
    parentInstance : Instance | Container,
    child : Instance | TextInstance,
    beforeChild : Instance | TextInstance
    ) : void {
    parentInstance.insertBefore(child, beforeChild);
    },
    removeChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
    parentInstance.removeChild(child);
    },
    scheduleAnimationCallback: window.requestAnimationFrame,
    scheduleDeferredCallback: window.requestIdleCallback,
    useSyncScheduling: true,

@leoselig
Copy link
Contributor

leoselig commented Aug 23, 2017

@gaearon
With the first beta releases of Fiber going out I was wondering if the custom renderer API is documented somewhere already or if there is any place to track progress of it.

Your much quoted tweet gave some great outlook already but it seems somewhat outdated by now and not sufficient to actually start digging into the topic

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

4 participants