@@ -28,6 +28,7 @@ var ReactReifiedYield = require('ReactReifiedYield');
2828var ReactTypeOfSideEffect = require ( 'ReactTypeOfSideEffect' ) ;
2929var ReactTypeOfWork = require ( 'ReactTypeOfWork' ) ;
3030
31+ var emptyObject = require ( 'emptyObject' ) ;
3132var getIteratorFn = require ( 'getIteratorFn' ) ;
3233
3334const {
@@ -47,6 +48,7 @@ const {
4748const isArray = Array . isArray ;
4849
4950const {
51+ ClassComponent,
5052 HostText,
5153 CoroutineComponent,
5254 YieldComponent,
@@ -62,6 +64,31 @@ const {
6264 Deletion,
6365} = ReactTypeOfSideEffect ;
6466
67+ function transferRef ( current : ?Fiber , workInProgress : Fiber , element : ReactElement < any > ) {
68+ if ( typeof element . ref === 'string' ) {
69+ if ( element . _owner ) {
70+ const ownerFiber : ?Fiber = ( element . _owner : any ) ;
71+ if ( ownerFiber && ownerFiber . tag === ClassComponent ) {
72+ const stringRef = element . ref ;
73+ // Check if previous string ref matches new string ref
74+ if ( current && current . ref && current . ref . _stringRef === stringRef ) {
75+ workInProgress . ref = current . ref ;
76+ return ;
77+ }
78+ const inst = ownerFiber . stateNode ;
79+ const ref = function ( value ) {
80+ const refs = inst . refs === emptyObject ? ( inst . refs = { } ) : inst . refs ;
81+ refs [ stringRef ] = value ;
82+ }
83+ ref . _stringRef = stringRef ;
84+ workInProgress . ref = ref ;
85+ }
86+ }
87+ } else {
88+ workInProgress . ref = element . ref ;
89+ }
90+ }
91+
6592// This wrapper function exists because I expect to clone the code in each path
6693// to be able to optimize each path individually by branching early. This needs
6794// a compiler or we can do it manually. Helpers that don't need this branching
@@ -221,13 +248,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
221248 if ( current == null || current . type !== element . type ) {
222249 // Insert
223250 const created = createFiberFromElement ( element , priority ) ;
224- created . ref = element . ref ;
251+ transferRef ( current , created , element ) ;
225252 created . return = returnFiber ;
226253 return created ;
227254 } else {
228255 // Move based on index
229256 const existing = useFiber ( current , priority ) ;
230- existing . ref = element . ref ;
257+ transferRef ( current , existing , element ) ;
231258 existing . pendingProps = element . props ;
232259 existing . return = returnFiber ;
233260 return existing ;
@@ -319,7 +346,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
319346 switch ( newChild . $$typeof ) {
320347 case REACT_ELEMENT_TYPE : {
321348 const created = createFiberFromElement ( newChild , priority ) ;
322- created . ref = newChild . ref ;
349+ transferRef ( null , created , newChild ) ;
323350 created . return = returnFiber ;
324351 return created ;
325352 }
@@ -653,7 +680,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
653680 if ( child . type === element . type ) {
654681 deleteRemainingChildren ( returnFiber , child . sibling ) ;
655682 const existing = useFiber ( child , priority ) ;
656- existing . ref = element . ref ;
683+ transferRef ( child , existing , element ) ;
657684 existing . pendingProps = element . props ;
658685 existing . return = returnFiber ;
659686 return existing ;
@@ -668,7 +695,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) {
668695 }
669696
670697 const created = createFiberFromElement ( element , priority ) ;
671- created . ref = element . ref ;
698+ transferRef ( currentFirstChild , created , element ) ;
672699 created . return = returnFiber ;
673700 return created ;
674701 }
0 commit comments