-
Notifications
You must be signed in to change notification settings - Fork 45.6k
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
[Fiber] String refs and owner tracking #8099
Changes from all commits
aa14cc2
338683f
d3fb83c
376b8f3
68c0915
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,6 +28,7 @@ var ReactReifiedYield = require('ReactReifiedYield'); | |
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect'); | ||
var ReactTypeOfWork = require('ReactTypeOfWork'); | ||
|
||
var emptyObject = require('emptyObject'); | ||
var getIteratorFn = require('getIteratorFn'); | ||
|
||
const { | ||
|
@@ -47,6 +48,7 @@ const { | |
const isArray = Array.isArray; | ||
|
||
const { | ||
ClassComponent, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I imported it for this purpose but forgot: https://github.com/facebook/react/pull/8099/files#r85031873 :D |
||
HostText, | ||
CoroutineComponent, | ||
YieldComponent, | ||
|
@@ -62,6 +64,31 @@ const { | |
Deletion, | ||
} = ReactTypeOfSideEffect; | ||
|
||
function transferRef(current: ?Fiber, workInProgress: Fiber, element: ReactElement<any>) { | ||
if (typeof element.ref === 'string') { | ||
if (element._owner) { | ||
const ownerFiber : ?Fiber = (element._owner : any); | ||
if (ownerFiber && ownerFiber.tag === ClassComponent) { | ||
const stringRef = element.ref; | ||
// Check if previous string ref matches new string ref | ||
if (current && current.ref && current.ref._stringRef === stringRef) { | ||
workInProgress.ref = current.ref; | ||
return; | ||
} | ||
const inst = ownerFiber.stateNode; | ||
const ref = function(value) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function won't get a name. We should make any functions calling user code named for better stack traces. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Never mind, I misunderstood. This doesn't call into user code. |
||
const refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; | ||
refs[stringRef] = value; | ||
}; | ||
ref._stringRef = stringRef; | ||
workInProgress.ref = ref; | ||
} | ||
} | ||
} else { | ||
workInProgress.ref = element.ref; | ||
} | ||
} | ||
|
||
// This wrapper function exists because I expect to clone the code in each path | ||
// to be able to optimize each path individually by branching early. This needs | ||
// a compiler or we can do it manually. Helpers that don't need this branching | ||
|
@@ -221,13 +248,13 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { | |
if (current == null || current.type !== element.type) { | ||
// Insert | ||
const created = createFiberFromElement(element, priority); | ||
created.ref = element.ref; | ||
transferRef(current, created, element); | ||
created.return = returnFiber; | ||
return created; | ||
} else { | ||
// Move based on index | ||
const existing = useFiber(current, priority); | ||
existing.ref = element.ref; | ||
transferRef(current, existing, element); | ||
existing.pendingProps = element.props; | ||
existing.return = returnFiber; | ||
return existing; | ||
|
@@ -319,7 +346,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { | |
switch (newChild.$$typeof) { | ||
case REACT_ELEMENT_TYPE: { | ||
const created = createFiberFromElement(newChild, priority); | ||
created.ref = newChild.ref; | ||
transferRef(null, created, newChild); | ||
created.return = returnFiber; | ||
return created; | ||
} | ||
|
@@ -653,7 +680,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { | |
if (child.type === element.type) { | ||
deleteRemainingChildren(returnFiber, child.sibling); | ||
const existing = useFiber(child, priority); | ||
existing.ref = element.ref; | ||
transferRef(child, existing, element); | ||
existing.pendingProps = element.props; | ||
existing.return = returnFiber; | ||
return existing; | ||
|
@@ -668,7 +695,7 @@ function ChildReconciler(shouldClone, shouldTrackSideEffects) { | |
} | ||
|
||
const created = createFiberFromElement(element, priority); | ||
created.ref = element.ref; | ||
transferRef(currentFirstChild, created, element); | ||
created.return = returnFiber; | ||
return created; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ import type { ReactCoroutine } from 'ReactCoroutine'; | |
import type { Fiber } from 'ReactFiber'; | ||
import type { HostConfig } from 'ReactFiberReconciler'; | ||
import type { PriorityLevel } from 'ReactPriorityLevel'; | ||
import ReactCurrentOwner from 'ReactCurrentOwner'; | ||
|
||
var { | ||
mountChildFibersInPlace, | ||
|
@@ -151,7 +152,12 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, s | |
} | ||
} | ||
|
||
var nextChildren = fn(props); | ||
if (__DEV__) { | ||
ReactCurrentOwner.current = workInProgress; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought we decided that we didn't need this for functional components? EDIT: Oh, it is DEV only. nvm. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought what we decided was we didn't need it when constructing a class component. Still need it for rendering a functional component. Might be best to remove this until it's actually needed regardless. |
||
var nextChildren = fn(props); | ||
} else { | ||
var nextChildren = fn(props); | ||
} | ||
reconcileChildren(current, workInProgress, nextChildren); | ||
return workInProgress.child; | ||
} | ||
|
@@ -176,6 +182,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, s | |
} | ||
// Rerender | ||
const instance = workInProgress.stateNode; | ||
ReactCurrentOwner.current = workInProgress; | ||
const nextChildren = instance.render(); | ||
reconcileChildren(current, workInProgress, nextChildren); | ||
return workInProgress.child; | ||
|
@@ -237,12 +244,20 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, s | |
} | ||
var fn = workInProgress.type; | ||
var props = workInProgress.pendingProps; | ||
var value = fn(props); | ||
|
||
if (__DEV__) { | ||
ReactCurrentOwner.current = workInProgress; | ||
var value = fn(props); | ||
} else { | ||
var value = fn(props); | ||
} | ||
|
||
if (typeof value === 'object' && value && typeof value.render === 'function') { | ||
// Proceed under the assumption that this is a class instance | ||
workInProgress.tag = ClassComponent; | ||
adoptClassInstance(workInProgress, value); | ||
mountClassInstance(workInProgress); | ||
ReactCurrentOwner.current = workInProgress; | ||
value = value.render(); | ||
} else { | ||
// Proceed under the assumption that this is a functional component | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm actually about to try to make this file work with Fiber but this is fine too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah tbh I barely looked at what this file does; just trying to get it merged for now :D