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

Consider exposing ReactElement factory function #8431

Closed
thheller opened this issue Nov 27, 2016 · 4 comments
Closed

Consider exposing ReactElement factory function #8431

thheller opened this issue Nov 27, 2016 · 4 comments

Comments

@thheller
Copy link

Currently React exposes React.createElement(type, config, children) [1] to the outside world and internally calls the ReactElement(type, key, ref, self, source, owner, props) [2] function to create the actual Element instance.

React.createElement performs a copy of config to create props and extract key and ref.

In the ClojureScript world many libraries wrap React to provide a more cljs-idiomatic interface using CLJS persistent maps for props. The "hiccup"-syntax is very popular and convenient.

[:div {:key "my-key" :ref my-ref-fn :other "props"}
  [:h1 "text]]

While this is far from ideal since we first allocate the CLJS data structures in addition to just ReactElements it is particular inconvenient that we convert the props data once and React does again. It would safe a lot of overhead if you could just call ReactElement directly saving a whole lot of work.

React.createElementRaw(type, key, ref, props) would be nice (as the others would be null anyways) or maybe under a more obscure name (to discourage use). It is fine if this is marked experimental and not otherwise officially supported.

Happy to create a matching PR if you folks agree to expose this somewhere.

[1]

ReactElement.createElement = function(type, config, children) {
var propName;
// Reserved names are extracted
var props = {};
var key = null;
var ref = null;
var self = null;
var source = null;
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)) {
props[propName] = config[propName];
}
}
}
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
var childrenLength = arguments.length - 2;
if (childrenLength === 1) {
props.children = children;
} else if (childrenLength > 1) {
var childArray = Array(childrenLength);
for (var i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) {
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
// Resolve default props
if (type && type.defaultProps) {
var defaultProps = type.defaultProps;
for (propName in defaultProps) {
if (props[propName] === undefined) {
props[propName] = defaultProps[propName];
}
}
}
if (__DEV__) {
if (key || ref) {
if (typeof props.$$typeof === 'undefined' ||
props.$$typeof !== REACT_ELEMENT_TYPE) {
var displayName = typeof type === 'function' ?
(type.displayName || type.name || 'Unknown') :
type;
if (key) {
defineKeyPropWarningGetter(props, displayName);
}
if (ref) {
defineRefPropWarningGetter(props, displayName);
}
}
}
}
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props
);
};

[2]
var ReactElement = function(type, key, ref, self, source, owner, props) {

@gaearon
Copy link
Collaborator

gaearon commented Nov 27, 2016

If you're only optimizing it in production, would it make sense to skip React altogether and generate plain objects like Babel does with this plugin? See also #3228.

@thheller
Copy link
Author

Yes, that would be my solution as well. However given that React already has this function I thought I'd ask to make it accessible.

@thheller
Copy link
Author

Oh and ReactCurrentOwner.current is not available when creating the element manually. Not sure how relevant that is, seems to be required for refs?

@gaearon
Copy link
Collaborator

gaearon commented Oct 4, 2017

It's only required for string refs, and those will eventually get deprecated anyway.

I encourage you to just generate those objects directly.

@gaearon gaearon closed this as completed Oct 4, 2017
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

2 participants