jiuyiUniapp/service/node_modules/react-native/ReactCommon/react/nativemodule/mutationobserver/NativeMutationObserver.cpp

161 lines
5.4 KiB
C++
Raw Normal View History

2025-02-13 09:59:20 +08:00
/*
* 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 "NativeMutationObserver.h"
#include <cxxreact/SystraceSection.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/renderer/core/ShadowNode.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/primitives.h>
#include "Plugins.h"
std::shared_ptr<facebook::react::TurboModule>
NativeMutationObserverModuleProvider(
std::shared_ptr<facebook::react::CallInvoker> jsInvoker) {
return std::make_shared<facebook::react::NativeMutationObserver>(
std::move(jsInvoker));
}
namespace facebook::react {
static UIManager& getUIManagerFromRuntime(jsi::Runtime& runtime) {
return UIManagerBinding::getBinding(runtime)->getUIManager();
}
NativeMutationObserver::NativeMutationObserver(
std::shared_ptr<CallInvoker> jsInvoker)
: NativeMutationObserverCxxSpec(std::move(jsInvoker)) {}
void NativeMutationObserver::observe(
jsi::Runtime& runtime,
NativeMutationObserverObserveOptions options) {
auto mutationObserverId = options.mutationObserverId;
auto subtree = options.subtree;
auto shadowNode =
shadowNodeFromValue(runtime, std::move(options).targetShadowNode);
auto& uiManager = getUIManagerFromRuntime(runtime);
mutationObserverManager_.observe(
mutationObserverId, shadowNode, subtree, uiManager);
}
void NativeMutationObserver::unobserve(
jsi::Runtime& runtime,
MutationObserverId mutationObserverId,
jsi::Object targetShadowNode) {
auto shadowNode = shadowNodeFromValue(runtime, std::move(targetShadowNode));
mutationObserverManager_.unobserve(mutationObserverId, *shadowNode);
}
void NativeMutationObserver::connect(
jsi::Runtime& runtime,
jsi::Function notifyMutationObservers,
SyncCallback<jsi::Value(jsi::Value)> getPublicInstanceFromInstanceHandle) {
auto& uiManager = getUIManagerFromRuntime(runtime);
runtime_ = &runtime;
notifyMutationObservers_.emplace(std::move(notifyMutationObservers));
getPublicInstanceFromInstanceHandle_.emplace(
std::move(getPublicInstanceFromInstanceHandle));
auto onMutationsCallback = [&](std::vector<MutationRecord>& records) {
return onMutations(records);
};
mutationObserverManager_.connect(uiManager, std::move(onMutationsCallback));
}
void NativeMutationObserver::disconnect(jsi::Runtime& runtime) {
auto& uiManager = getUIManagerFromRuntime(runtime);
mutationObserverManager_.disconnect(uiManager);
runtime_ = nullptr;
notifyMutationObservers_.reset();
getPublicInstanceFromInstanceHandle_.reset();
}
std::vector<NativeMutationRecord> NativeMutationObserver::takeRecords(
jsi::Runtime& /*runtime*/) {
notifiedMutationObservers_ = false;
std::vector<NativeMutationRecord> records;
pendingRecords_.swap(records);
return records;
}
jsi::Value NativeMutationObserver::getPublicInstanceFromShadowNode(
const ShadowNode& shadowNode) const {
auto instanceHandle = shadowNode.getInstanceHandle(*runtime_);
if (!instanceHandle.isObject()) {
return jsi::Value::null();
}
return getPublicInstanceFromInstanceHandle_.value().call(
std::move(instanceHandle));
}
std::vector<jsi::Value>
NativeMutationObserver::getPublicInstancesFromShadowNodes(
const std::vector<ShadowNode::Shared>& shadowNodes) const {
std::vector<jsi::Value> publicInstances;
publicInstances.reserve(shadowNodes.size());
for (const auto& shadowNode : shadowNodes) {
publicInstances.push_back(getPublicInstanceFromShadowNode(*shadowNode));
}
return publicInstances;
}
void NativeMutationObserver::onMutations(std::vector<MutationRecord>& records) {
SystraceSection s("NativeMutationObserver::onMutations");
for (const auto& record : records) {
pendingRecords_.emplace_back(NativeMutationRecord{
record.mutationObserverId,
// FIXME(T157129303) Instead of assuming we can call into JS from here,
// we should use an API that explicitly indicates it.
getPublicInstanceFromShadowNode(*record.targetShadowNode),
getPublicInstancesFromShadowNodes(record.addedShadowNodes),
getPublicInstancesFromShadowNodes(record.removedShadowNodes)});
}
notifyMutationObserversIfNecessary();
}
/**
* This method allows us to avoid scheduling multiple calls to notify observers
* in the JS thread. We schedule one and skip subsequent ones (we just append
* the records to the pending list and wait for the scheduled task to consume
* all of them).
*/
void NativeMutationObserver::notifyMutationObserversIfNecessary() {
bool dispatchNotification = false;
if (!pendingRecords_.empty() && !notifiedMutationObservers_) {
notifiedMutationObservers_ = true;
dispatchNotification = true;
}
if (dispatchNotification) {
SystraceSection s("NativeMutationObserver::notifyObservers");
if (ReactNativeFeatureFlags::enableBridgelessArchitecture() &&
!ReactNativeFeatureFlags::disableEventLoopOnBridgeless()) {
runtime_->queueMicrotask(notifyMutationObservers_.value());
} else {
jsInvoker_->invokeAsync([&](jsi::Runtime& runtime) {
// It's possible that the last observer was disconnected before we could
// dispatch this notification.
if (notifyMutationObservers_) {
notifyMutationObservers_.value().call(runtime);
}
});
}
}
}
} // namespace facebook::react