mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/37553 ## Context I added some getters in EventTarget/EventEmitter to access the React instance handle for a given shadow node/shadow node family in https://github.com/facebook/react-native/commit/43864a1d6025bfc4483dded115d51f7613018199 (D44022477), so I could implement DOM traversal methods easily. I wanted to reuse that method to implement `MutationObserver` and `IntersectionObserver`, but unfortunately `EventEmitter`/`EventTarget` only allow access to the instance handle as long as the shadow node is mounted. That makes sense for events, but not for this use case, as with `MutationObserver` we intentionally want to have access to unmounted nodes when creating the list of `addedNodes` and `removedNodes` for the `MutationRecord` (depending on when exactly we generate this list, either `addedNodes` or `removedNodes` wouldn't be mounted). ## Changes This reverts my original change and adds a new field in `ShadowNodeFamily` to provide access to the `InstanceHandle` at any point (even if the node isn't mounted). This provides the same guarantees as the original method, keeping weak references to the handles to avoid memory leaks. Changelog: [internal] Reviewed By: sammy-SC Differential Revision: D46149084 fbshipit-source-id: f76abae50134a5d55a98cab42eebeb62084024f9
163 lines
5.3 KiB
C++
163 lines
5.3 KiB
C++
/*
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#include "ComponentDescriptorRegistry.h"
|
|
|
|
#include "componentNameByReactViewName.h"
|
|
|
|
#include <react/debug/react_native_assert.h>
|
|
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
|
|
#include <react/renderer/core/PropsParserContext.h>
|
|
#include <react/renderer/core/ShadowNodeFragment.h>
|
|
|
|
#include <utility>
|
|
|
|
namespace facebook::react {
|
|
|
|
ComponentDescriptorRegistry::ComponentDescriptorRegistry(
|
|
ComponentDescriptorParameters parameters,
|
|
ComponentDescriptorProviderRegistry const &providerRegistry,
|
|
ContextContainer::Shared contextContainer)
|
|
: parameters_(std::move(parameters)),
|
|
providerRegistry_(providerRegistry),
|
|
contextContainer_(std::move(contextContainer)) {}
|
|
|
|
void ComponentDescriptorRegistry::add(
|
|
ComponentDescriptorProvider componentDescriptorProvider) const {
|
|
std::unique_lock lock(mutex_);
|
|
|
|
auto componentDescriptor = componentDescriptorProvider.constructor(
|
|
{parameters_.eventDispatcher,
|
|
parameters_.contextContainer,
|
|
componentDescriptorProvider.flavor});
|
|
react_native_assert(
|
|
componentDescriptor->getComponentHandle() ==
|
|
componentDescriptorProvider.handle);
|
|
react_native_assert(
|
|
componentDescriptor->getComponentName() ==
|
|
componentDescriptorProvider.name);
|
|
|
|
auto sharedComponentDescriptor = std::shared_ptr<ComponentDescriptor const>(
|
|
std::move(componentDescriptor));
|
|
_registryByHandle[componentDescriptorProvider.handle] =
|
|
sharedComponentDescriptor;
|
|
_registryByName[componentDescriptorProvider.name] = sharedComponentDescriptor;
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::registerComponentDescriptor(
|
|
const SharedComponentDescriptor &componentDescriptor) const {
|
|
ComponentHandle componentHandle = componentDescriptor->getComponentHandle();
|
|
_registryByHandle[componentHandle] = componentDescriptor;
|
|
|
|
ComponentName componentName = componentDescriptor->getComponentName();
|
|
_registryByName[componentName] = componentDescriptor;
|
|
}
|
|
|
|
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|
std::string const &componentName) const {
|
|
std::shared_lock lock(mutex_);
|
|
|
|
auto unifiedComponentName = componentNameByReactViewName(componentName);
|
|
|
|
auto it = _registryByName.find(unifiedComponentName);
|
|
if (it == _registryByName.end()) {
|
|
lock.unlock();
|
|
providerRegistry_.request(unifiedComponentName.c_str());
|
|
lock.lock();
|
|
|
|
it = _registryByName.find(unifiedComponentName);
|
|
|
|
/*
|
|
* TODO: T54849676
|
|
* Uncomment the `assert` after the following block that checks
|
|
* `_fallbackComponentDescriptor` is no longer needed. The assert assumes
|
|
* that `componentDescriptorProviderRequest` is always not null and register
|
|
* some component on every single request.
|
|
*/
|
|
// assert(it != _registryByName.end());
|
|
}
|
|
|
|
if (it == _registryByName.end()) {
|
|
if (_fallbackComponentDescriptor == nullptr) {
|
|
throw std::invalid_argument(
|
|
("Unable to find componentDescriptor for " + unifiedComponentName)
|
|
.c_str());
|
|
}
|
|
return *_fallbackComponentDescriptor.get();
|
|
}
|
|
|
|
return *it->second;
|
|
}
|
|
|
|
ComponentDescriptor const *ComponentDescriptorRegistry::
|
|
findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock lock(mutex_);
|
|
|
|
auto iterator = _registryByHandle.find(componentHandle);
|
|
if (iterator == _registryByHandle.end()) {
|
|
return nullptr;
|
|
}
|
|
|
|
return iterator->second.get();
|
|
}
|
|
|
|
ComponentDescriptor const &ComponentDescriptorRegistry::at(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock lock(mutex_);
|
|
|
|
return *_registryByHandle.at(componentHandle);
|
|
}
|
|
|
|
bool ComponentDescriptorRegistry::hasComponentDescriptorAt(
|
|
ComponentHandle componentHandle) const {
|
|
std::shared_lock lock(mutex_);
|
|
|
|
auto iterator = _registryByHandle.find(componentHandle);
|
|
return iterator != _registryByHandle.end();
|
|
}
|
|
|
|
ShadowNode::Shared ComponentDescriptorRegistry::createNode(
|
|
Tag tag,
|
|
std::string const &viewName,
|
|
SurfaceId surfaceId,
|
|
folly::dynamic const &propsDynamic,
|
|
InstanceHandle::Shared const &instanceHandle) const {
|
|
auto unifiedComponentName = componentNameByReactViewName(viewName);
|
|
auto const &componentDescriptor = this->at(unifiedComponentName);
|
|
|
|
auto const fragment =
|
|
ShadowNodeFamilyFragment{tag, surfaceId, instanceHandle};
|
|
auto family = componentDescriptor.createFamily(fragment);
|
|
auto const props = componentDescriptor.cloneProps(
|
|
PropsParserContext{surfaceId, *contextContainer_.get()},
|
|
nullptr,
|
|
RawProps(propsDynamic));
|
|
auto const state = componentDescriptor.createInitialState(props, family);
|
|
|
|
return componentDescriptor.createShadowNode(
|
|
{
|
|
/* .props = */ props,
|
|
/* .children = */ ShadowNodeFragment::childrenPlaceholder(),
|
|
/* .state = */ state,
|
|
},
|
|
family);
|
|
}
|
|
|
|
void ComponentDescriptorRegistry::setFallbackComponentDescriptor(
|
|
const SharedComponentDescriptor &descriptor) {
|
|
_fallbackComponentDescriptor = descriptor;
|
|
registerComponentDescriptor(descriptor);
|
|
}
|
|
|
|
ComponentDescriptor::Shared
|
|
ComponentDescriptorRegistry::getFallbackComponentDescriptor() const {
|
|
return _fallbackComponentDescriptor;
|
|
}
|
|
|
|
} // namespace facebook::react
|