Use react-dom/client createRoot

This commit is contained in:
Fedor Indutny 2025-07-15 16:32:11 -07:00 committed by GitHub
parent 26933bf8d7
commit b30c53d291
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 51 additions and 46 deletions

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { isNumber, groupBy, throttle } from 'lodash';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import PQueue from 'p-queue';
import pMap from 'p-map';
import { v7 as generateUuid } from 'uuid';
@ -1552,9 +1552,11 @@ export async function startApp(): Promise<void> {
await runAllSyncTasks();
cancelInitializationMessage();
render(
window.Signal.State.Roots.createApp(window.reduxStore),
document.getElementById('app-container')
const appContainer = document.getElementById('app-container');
strictAssert(appContainer != null, 'No #app-container');
createRoot(appContainer).render(
window.Signal.State.Roots.createApp(window.reduxStore)
);
const hideMenuBar = window.storage.get('hide-menu-bar', false);
window.IPC.setAutoHideMenuBar(hideMenuBar);

View file

@ -1,7 +1,8 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { render, unmountComponentAtNode } from 'react-dom';
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import type { ConversationAttributesType } from '../model-types.d';
import type { ConversationModel } from '../models/conversations';
@ -389,9 +390,8 @@ export async function joinViaLink(value: string): Promise<void> {
let groupV2InfoNode: HTMLDivElement | undefined =
document.createElement('div');
render(
createGroupV2JoinModal(window.reduxStore, { join, onClose: closeDialog }),
groupV2InfoNode
createRoot(groupV2InfoNode).render(
createGroupV2JoinModal(window.reduxStore, { join, onClose: closeDialog })
);
// We declare a new function here so we can await but not block

View file

@ -3,7 +3,7 @@
import React, { StrictMode } from 'react';
import EmbedBlot from '@signalapp/quill-cjs/blots/embed';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { Emojify } from '../../components/conversation/Emojify';
import { normalizeAci } from '../../util/normalizeAci';
@ -46,7 +46,7 @@ export class MentionBlot extends EmbedBlot {
const mentionSpan = document.createElement('span');
render(
createRoot(mentionSpan).render(
<StrictMode>
<FunEmojiLocalizationProvider i18n={window.i18n}>
<span className="module-composition-input__at-mention">
@ -56,8 +56,7 @@ export class MentionBlot extends EmbedBlot {
</bdi>
</span>
</FunEmojiLocalizationProvider>
</StrictMode>,
mentionSpan
</StrictMode>
);
node.appendChild(mentionSpan);

View file

@ -2,19 +2,21 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { ClearingData } from '../components/ClearingData';
import { strictAssert } from '../util/assert';
import { deleteAllData } from './deleteAllData';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
export function renderClearingDataView(): void {
render(
const appContainer = document.getElementById('app-container');
strictAssert(appContainer != null, 'No #app-container');
createRoot(appContainer).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<ClearingData deleteAllData={deleteAllData} i18n={window.i18n} />
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
document.getElementById('app-container')
</StrictMode>
);
}

View file

@ -2,7 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import * as Errors from '../types/errors';
import { createLogger } from '../logging/log';
@ -34,13 +35,12 @@ export async function longRunningTaskWrapper<T>({
progressNode = document.createElement('div');
log.info(`${idLog}: Creating spinner`);
render(
createRoot(progressNode).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<ProgressModal i18n={window.i18n} />
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
progressNode
</StrictMode>
);
spinnerStart = Date.now();
}, TWO_SECONDS);

View file

@ -2,7 +2,8 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { unmountComponentAtNode } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { ConfirmationDialog } from '../components/ConfirmationDialog';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../components/fun/FunEmojiLocalizationProvider';
@ -55,7 +56,7 @@ export function showConfirmationDialog(
confirmationDialogPreviousFocus = document.activeElement as HTMLElement;
render(
createRoot(confirmationDialogViewNode).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<ConfirmationDialog
@ -88,7 +89,6 @@ export function showConfirmationDialog(
{options.description}
</ConfirmationDialog>
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
confirmationDialogViewNode
</StrictMode>
);
}

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { About } from '../../components/About';
import { i18n } from '../sandboxedInit';
@ -13,7 +13,10 @@ const { AboutWindowProps } = window.Signal;
strictAssert(AboutWindowProps, 'window values not provided');
ReactDOM.render(
const app = document.getElementById('app');
strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<About
@ -25,6 +28,5 @@ ReactDOM.render(
version={window.SignalContext.getVersion()}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
document.getElementById('app')
</StrictMode>
);

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import { render } from 'react-dom';
import { createRoot } from 'react-dom/client';
import { DebugLogWindow } from '../../components/DebugLogWindow';
import { FunDefaultEnglishEmojiLocalizationProvider } from '../../components/fun/FunEmojiLocalizationProvider';
import { i18n } from '../sandboxedInit';
@ -12,7 +12,10 @@ const { DebugLogWindowProps } = window.Signal;
strictAssert(DebugLogWindowProps, 'window values not provided');
render(
const app = document.getElementById('app');
strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<DebugLogWindow
@ -23,6 +26,5 @@ render(
uploadLogs={DebugLogWindowProps.uploadLogs}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
document.getElementById('app')
</StrictMode>
);

View file

@ -3,8 +3,6 @@
import Backbone from 'backbone';
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import * as moment from 'moment';
// @ts-expect-error -- no types
import 'moment/min/locales.min';
@ -49,9 +47,6 @@ window.WebAPI = window.textsecure.WebAPI.initialize({
window.libphonenumberInstance = PhoneNumberUtil.getInstance();
window.libphonenumberFormat = PhoneNumberFormat;
window.React = React;
window.ReactDOM = ReactDOM;
const { resolvedTranslationsLocale, preferredSystemLocales, localeOverride } =
config;

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { PermissionsPopup } from '../../components/PermissionsPopup';
import { i18n } from '../sandboxedInit';
@ -26,7 +26,10 @@ if (forCalling) {
message = i18n('icu:audioPermissionNeeded');
}
ReactDOM.render(
const app = document.getElementById('app');
strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<PermissionsPopup
@ -36,6 +39,5 @@ ReactDOM.render(
onClose={PermissionsWindowProps.onClose}
/>
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
document.getElementById('app')
</StrictMode>
);

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom';
import { createRoot } from 'react-dom/client';
import { CallingScreenSharingController } from '../../components/CallingScreenSharingController';
import { i18n } from '../sandboxedInit';
@ -28,7 +28,10 @@ function render() {
// Pacify typescript
strictAssert(ScreenShareWindowProps, 'window values not provided');
ReactDOM.render(
const app = document.getElementById('app');
strictAssert(app != null, 'No #app');
createRoot(app).render(
<StrictMode>
<FunDefaultEnglishEmojiLocalizationProvider>
<div className="App dark-theme">
@ -41,9 +44,7 @@ function render() {
/>
</div>
</FunDefaultEnglishEmojiLocalizationProvider>
</StrictMode>,
document.getElementById('app')
</StrictMode>
);
}
render();