chainRef function
Returns a function that chains the callback or createRef-based ref of the provided element
with newCallbackRef
.
If there is no existing ref, newCallbackRef
is used.
Throws an ArgumentError if ReactElement.ref is a String ref.
TODO: This method makes assumptions about how react-dart does callback refs for dart components, so this method should be moved there (UIP-1118).
Implementation
CallbackRef? chainRef(ReactElement element, CallbackRef? newCallbackRef) {
final existingRef = element.ref as Object?;
// If there's no existing ref, just return the new one.
if (existingRef == null) return newCallbackRef;
if (existingRef is String) {
throw ArgumentError.value(existingRef, 'element.ref',
'The existing ref is a String ref and cannot be chained');
}
if (existingRef is Function) { // Callback refs
void chainedRef(ref) {
// For Dart components, the existing ref is a function passed to the JS that wraps the Dart
// callback ref and converts the JS instance to the Dart component.
// So, we need to undo the wrapping around this chained ref and pass in the JS instance.
existingRef(ref is react.Component ? ref.jsThis : ref); // ignore: deprecated_member_use
if (newCallbackRef != null) newCallbackRef(ref);
}
return chainedRef;
} else { // Assume it's a ref object created by createRef
assert(existingRef is! Ref,
'should be a JsRef; the factory that created `element` should never let a Dart ref get here');
void chainedRef(ref) {
// For Dart components, the existing ref is a Dart Ref object that converts
// the JS instance on the JS ref to the Dart component.
// So, we need to undo the wrapping around this chained ref and pass in the JS instance.
//
// Update `.current` manually on the ref object.
// As per https://github.com/facebook/react/issues/13029 it should be fine to set current this way.
// Use setProperty so we don't have to expose a `JsRef.current` setter, which could be misused.
setProperty(existingRef, 'current', ref is react.Component ? ref.jsThis : ref); // ignore: deprecated_member_use
if (newCallbackRef != null) newCallbackRef(ref);
}
return chainedRef;
}
}