{"action":"created","issue":{"url":"https://api.github.com/repos/facebook/react/issues/4296","labels_url":"https://api.github.com/repos/facebook/react/issues/4296/labels{/name}","comments_url":"https://api.github.com/repos/facebook/react/issues/4296/comments","events_url":"https://api.github.com/repos/facebook/react/issues/4296/events","html_url":"https://github.com/facebook/react/issues/4296","id":93197180,"number":4296,"title":"[Proposal] Automatically compose refs in cloneElement","user":{"login":"ide","id":379606,"avatar_url":"https://avatars.githubusercontent.com/u/379606?v=3","gravatar_id":"","url":"https://api.github.com/users/ide","html_url":"https://github.com/ide","followers_url":"https://api.github.com/users/ide/followers","following_url":"https://api.github.com/users/ide/following{/other_user}","gists_url":"https://api.github.com/users/ide/gists{/gist_id}","starred_url":"https://api.github.com/users/ide/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ide/subscriptions","organizations_url":"https://api.github.com/users/ide/orgs","repos_url":"https://api.github.com/users/ide/repos","events_url":"https://api.github.com/users/ide/events{/privacy}","received_events_url":"https://api.github.com/users/ide/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":3,"created_at":"2015-07-06T05:54:27Z","updated_at":"2015-07-06T21:47:23Z","closed_at":null,"body":"Currently `cloneElement` clobbers the original element's ref if you provide a new ref when cloning: https://github.com/facebook/react/blob/master/src/isomorphic/classic/element/ReactElement.js#L174. This is a proposal to automatically compose callback refs so that this works:\r\n\r\n```js\r\nvar original = <C ref={component => console.log('original ref') />;\r\nvar clone = React.cloneElement(original, {\r\n  ref: component => console.log('clone ref');\r\n});\r\n\r\n// upon mounting prints:\r\n// clone ref\r\n// original ref\r\n```\r\n\r\nThe implementation to compose refs would look similar to the technique used here: https://github.com/facebook/react-native/blob/fe9af98a2867475f5d4af9bbe49ce0ed0a7b1d08/Libraries/CustomComponents/Navigator/Navigator.js#L1041\r\n\r\n```js\r\nvar element = ...\r\nvar originalRef = element.ref;\r\nif (originalRef != null && typeof originalRef !== 'function') {\r\n  console.warn(\r\n    'String refs are not composable. Use a callback ' +\r\n    'ref instead. Ignoring ref: ' + originalRef\r\n  );\r\n  originalRef = null;\r\n}\r\n\r\nReact.cloneElement(element, {\r\n  ref: component => {\r\n    // Whatever you want here\r\n    \r\n    if (originalRef) {\r\n      originalRef(component);\r\n    }\r\n  }\r\n});\r\n```\r\n\r\nWhen writing higher-order components I find myself composing refs a lot and having to write this ref-composition code several times. Easy to write a utility helper (https://github.com/ide/react-native-clone-referenced-element/blob/master/cloneReferencedElement.js) but thought this could make sense to build in with 0.14 approaching. \r\n\r\ncc @spicyj @sebmarkbage "},"comment":{"url":"https://api.github.com/repos/facebook/react/issues/comments/119006488","html_url":"https://github.com/facebook/react/issues/4296#issuecomment-119006488","issue_url":"https://api.github.com/repos/facebook/react/issues/4296","id":119006488,"user":{"login":"sebmarkbage","id":63648,"avatar_url":"https://avatars.githubusercontent.com/u/63648?v=3","gravatar_id":"","url":"https://api.github.com/users/sebmarkbage","html_url":"https://github.com/sebmarkbage","followers_url":"https://api.github.com/users/sebmarkbage/followers","following_url":"https://api.github.com/users/sebmarkbage/following{/other_user}","gists_url":"https://api.github.com/users/sebmarkbage/gists{/gist_id}","starred_url":"https://api.github.com/users/sebmarkbage/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sebmarkbage/subscriptions","organizations_url":"https://api.github.com/users/sebmarkbage/orgs","repos_url":"https://api.github.com/users/sebmarkbage/repos","events_url":"https://api.github.com/users/sebmarkbage/events{/privacy}","received_events_url":"https://api.github.com/users/sebmarkbage/received_events","type":"User","site_admin":false},"created_at":"2015-07-06T21:47:23Z","updated_at":"2015-07-06T21:47:23Z","body":"My concern with chaining refs implicitly is that you may introduce subtle bugs by having two sources touching an imperative API. You can't reason about how they interact. It can also lead to subtle race conditions. There's no single source of truth of the state - which is what React is all about.\r\n\r\nI do agree that it is common for people to forget about the ref and that others might want access to it. However, I think that it is very important to make the choice explicitly. If they didn't, you can just ask them to do that explicitly or do it yourself. This is also one of the primary reasons we discourage `React.findDOMNode` for the benefit of direct refs since it allow you to by-pass the contract of a child and get access to a deeper ref.\r\n\r\nRegarding replacing refs with data binding, I think that every possible use case in React could be replaced by data binding. We know because there are so many FRP libraries that have done it and we know how to do it. We also know that can lead to massive complexity. It is very difficult for us to make the call when we should move towards that direction since we know how it usually turns out. That's why I think that we should be very hesitant with data binding, but pragmatic when we need to be (e.g. Animated) - i.e. not as a general direction of the project.\r\n\r\nrefs is an espace hatch. It allows us access to solutions we haven't thought about. If we think about them, even just briefly, I think we can come up with great alternatives. For example, there are some ideas around focus and selection using parent-based context.\r\n\r\nFor higher order components specifically, it is usually the case that you want a pass-through ref. The current alternative is to have pass-through proxy methods on the higher order component. See #4213 \r\n\r\nIt seems weird to use cloneElement with higher-order components. @ide can you elaborate on how you use it?\r\n\r\nFinally, `cloneElement` is mostly used as a way to pass extra props from a parent to child. However, that doesn't work through wrappers. This is one of the primary features of parent-based context so we expect a lot of uses of `cloneElement` to be replaced by parent-based context anyway. The exception is when you need a ref ofc."}}