@@ -76,19 +76,13 @@ winrt::Microsoft::ReactNative::IReactPropertyBag ReactContext::Properties() noex
76
76
77
77
void ReactContext::CallJSFunction (std::string &&module , std::string &&method, folly::dynamic &¶ms) noexcept {
78
78
if (auto instance = m_reactInstance.GetStrongPtr ()) {
79
- if (instance->State () == ReactInstanceState::Loaded) {
80
- if (auto fbInstance = instance->GetInnerInstance ()) {
81
- fbInstance->callJSFunction (std::move (module ), std::move (method), std::move (params));
82
- }
83
- }
79
+ instance->CallJsFunction (std::move (module ), std::move (method), std::move (params));
84
80
}
85
81
}
86
82
87
83
void ReactContext::DispatchEvent (int64_t viewTag, std::string &&eventName, folly::dynamic &&eventData) noexcept {
88
84
if (auto instance = m_reactInstance.GetStrongPtr ()) {
89
- if (instance->State () == ReactInstanceState::Loaded) {
90
- instance->DispatchEvent (viewTag, std::move (eventName), std::move (eventData));
91
- }
85
+ instance->DispatchEvent (viewTag, std::move (eventName), std::move (eventData));
92
86
}
93
87
}
94
88
@@ -371,6 +365,7 @@ void ReactInstanceWin::LoadJSBundles() noexcept {
371
365
instanceWrapper->loadBundleSync (Mso::Copy (options.Identity ));
372
366
} catch (...) {
373
367
strongThis->m_state = ReactInstanceState::HasError;
368
+ strongThis->AbandonJSCallQueue ();
374
369
strongThis->OnReactInstanceLoaded (Mso::ExceptionErrorProvider ().MakeErrorCode (std::current_exception ()));
375
370
return ;
376
371
}
@@ -390,8 +385,10 @@ void ReactInstanceWin::OnReactInstanceLoaded(const Mso::ErrorCode &errorCode) no
390
385
strongThis->m_isLoaded = true ;
391
386
if (!errorCode) {
392
387
strongThis->m_state = ReactInstanceState::Loaded;
388
+ strongThis->DrainJSCallQueue ();
393
389
} else {
394
390
strongThis->m_state = ReactInstanceState::HasError;
391
+ strongThis->AbandonJSCallQueue ();
395
392
}
396
393
397
394
if (auto onLoaded = strongThis->m_options .OnInstanceLoaded .Get ()) {
@@ -414,6 +411,8 @@ Mso::Future<void> ReactInstanceWin::Destroy() noexcept {
414
411
}
415
412
416
413
m_isDestroyed = true ;
414
+ m_state = ReactInstanceState::Unloaded;
415
+ AbandonJSCallQueue ();
417
416
418
417
if (!m_isLoaded) {
419
418
OnReactInstanceLoaded (Mso::CancellationErrorProvider ().MakeErrorCode (true ));
@@ -583,6 +582,7 @@ std::function<void(std::string)> ReactInstanceWin::GetErrorCallback() noexcept {
583
582
584
583
void ReactInstanceWin::OnErrorWithMessage (const std::string &errorMessage) noexcept {
585
584
m_state = ReactInstanceState::HasError;
585
+ AbandonJSCallQueue ();
586
586
587
587
if (m_redboxHandler && m_redboxHandler->isDevSupportEnabled ()) {
588
588
ErrorInfo errorInfo;
@@ -636,24 +636,63 @@ void ReactInstanceWin::OnDebuggerAttach() noexcept {
636
636
m_updateUI ();
637
637
}
638
638
639
+ void ReactInstanceWin::DrainJSCallQueue () noexcept {
640
+ // Handle all items in the queue one by one.
641
+ for (;;) {
642
+ JSCallEntry entry; // To avoid callJSFunction under the lock
643
+ {
644
+ std::scoped_lock lock{m_mutex};
645
+ if (m_state == ReactInstanceState::Loaded && !m_jsCallQueue.empty ()) {
646
+ entry = std::move (m_jsCallQueue.front ());
647
+ m_jsCallQueue.pop_front ();
648
+ } else {
649
+ break ;
650
+ }
651
+ }
652
+
653
+ if (auto instance = m_instance.LoadWithLock ()) {
654
+ instance->callJSFunction (std::move (entry.ModuleName ), std::move (entry.MethodName ), std::move (entry.Args ));
655
+ }
656
+ }
657
+ }
658
+
659
+ void ReactInstanceWin::AbandonJSCallQueue () noexcept {
660
+ std::deque<JSCallEntry> jsCallQueue; // To avoid destruction under the lock
661
+ {
662
+ std::scoped_lock lock{m_mutex};
663
+ if (m_state == ReactInstanceState::HasError || m_state == ReactInstanceState::Unloaded) {
664
+ jsCallQueue = std::move (m_jsCallQueue);
665
+ }
666
+ }
667
+ }
668
+
639
669
void ReactInstanceWin::CallJsFunction (
640
670
std::string &&moduleName,
641
671
std::string &&method,
642
672
folly::dynamic &¶ms) noexcept {
643
- // callJSFunction can be called from any thread. The native bridge will post the call to the right queue internally.
644
- if (m_state == ReactInstanceState::Loaded) {
673
+ bool shouldCall{false }; // To call callJSFunction outside of lock
674
+ {
675
+ std::scoped_lock lock{m_mutex};
676
+ if (m_state == ReactInstanceState::Loaded && m_jsCallQueue.empty ()) {
677
+ shouldCall = true ;
678
+ } else if (
679
+ m_state == ReactInstanceState::Loading || m_state == ReactInstanceState::WaitingForDebugger ||
680
+ (m_state == ReactInstanceState::Loaded && !m_jsCallQueue.empty ())) {
681
+ m_jsCallQueue.push_back (JSCallEntry{std::move (moduleName), std::move (method), std::move (params)});
682
+ }
683
+ // otherwise ignore the call
684
+ }
685
+
686
+ if (shouldCall) {
645
687
if (auto instance = m_instance.LoadWithLock ()) {
646
688
instance->callJSFunction (std::move (moduleName), std::move (method), std::move (params));
647
689
}
648
690
}
649
691
}
650
692
651
693
void ReactInstanceWin::DispatchEvent (int64_t viewTag, std::string &&eventName, folly::dynamic &&eventData) noexcept {
652
- if (m_state == ReactInstanceState::Loaded) {
653
- if (auto instance = m_instanceWrapper.LoadWithLock ()) {
654
- instance->DispatchEvent (viewTag, eventName, std::move (eventData));
655
- }
656
- }
694
+ folly::dynamic params = folly::dynamic::array (viewTag, std::move (eventName), std::move (eventData));
695
+ CallJsFunction (" RCTEventEmitter" , " receiveEvent" , std::move (params));
657
696
}
658
697
659
698
facebook::react::INativeUIManager *ReactInstanceWin::NativeUIManager () noexcept {
0 commit comments