Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

disable react strict mode for event loop #4720

Merged
merged 12 commits into from
Feb 1, 2025
14 changes: 7 additions & 7 deletions reflex/.templates/jinja/web/pages/_app.js.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ export default function MyApp({ Component, pageProps }) {
}, []);
return (
<ThemeProvider defaultTheme={ defaultColorMode } attribute="class">
<AppWrap>
<StateProvider>
<EventLoopProvider>
<Component {...pageProps} />
</EventLoopProvider>
</StateProvider>
</AppWrap>
<StateProvider>
<EventLoopProvider>
<AppWrap>
<Component {...pageProps} />
</AppWrap>
</EventLoopProvider>
</StateProvider>
</ThemeProvider>
);
}
Expand Down
69 changes: 40 additions & 29 deletions reflex/.templates/web/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,8 @@ export const applyEvent = async (event, socket) => {
a.href = eval?.(
event.payload.url.replace(
"getBackendURL(env.UPLOAD)",
`"${getBackendURL(env.UPLOAD)}"`
)
`"${getBackendURL(env.UPLOAD)}"`,
),
);
}
a.download = event.payload.filename;
Expand Down Expand Up @@ -341,7 +341,7 @@ export const applyRestEvent = async (event, socket) => {
event.payload.files,
event.payload.upload_id,
event.payload.on_upload_progress,
socket
socket,
);
return false;
}
Expand Down Expand Up @@ -408,7 +408,7 @@ export const connect = async (
dispatch,
transports,
setConnectErrors,
client_storage = {}
client_storage = {},
) => {
// Get backend URL object from the endpoint.
const endpoint = getBackendURL(EVENTURL);
Expand Down Expand Up @@ -499,7 +499,7 @@ export const uploadFiles = async (
files,
upload_id,
on_upload_progress,
socket
socket,
) => {
// return if there's no file to upload
if (files === undefined || files.length === 0) {
Expand Down Expand Up @@ -604,7 +604,7 @@ export const Event = (
name,
payload = {},
event_actions = {},
handler = null
handler = null,
) => {
return { name, payload, handler, event_actions };
};
Expand All @@ -631,7 +631,7 @@ export const hydrateClientStorage = (client_storage) => {
for (const state_key in client_storage.local_storage) {
const options = client_storage.local_storage[state_key];
const local_storage_value = localStorage.getItem(
options.name || state_key
options.name || state_key,
);
if (local_storage_value !== null) {
client_storage_values[state_key] = local_storage_value;
Expand All @@ -642,7 +642,7 @@ export const hydrateClientStorage = (client_storage) => {
for (const state_key in client_storage.session_storage) {
const session_options = client_storage.session_storage[state_key];
const session_storage_value = sessionStorage.getItem(
session_options.name || state_key
session_options.name || state_key,
);
if (session_storage_value != null) {
client_storage_values[state_key] = session_storage_value;
Expand All @@ -667,7 +667,7 @@ export const hydrateClientStorage = (client_storage) => {
const applyClientStorageDelta = (client_storage, delta) => {
// find the main state and check for is_hydrated
const unqualified_states = Object.keys(delta).filter(
(key) => key.split(".").length === 1
(key) => key.split(".").length === 1,
);
if (unqualified_states.length === 1) {
const main_state = delta[unqualified_states[0]];
Expand Down Expand Up @@ -701,7 +701,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
const session_options = client_storage.session_storage[state_key];
sessionStorage.setItem(
session_options.name || state_key,
delta[substate][key]
delta[substate][key],
);
}
}
Expand All @@ -721,7 +721,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
export const useEventLoop = (
dispatch,
initial_events = () => [],
client_storage = {}
client_storage = {},
) => {
const socket = useRef(null);
const router = useRouter();
Expand All @@ -735,7 +735,7 @@ export const useEventLoop = (

event_actions = events.reduce(
(acc, e) => ({ ...acc, ...e.event_actions }),
event_actions ?? {}
event_actions ?? {},
);

const _e = args.filter((o) => o?.preventDefault !== undefined)[0];
Expand Down Expand Up @@ -763,7 +763,7 @@ export const useEventLoop = (
debounce(
combined_name,
() => queueEvents(events, socket),
event_actions.debounce
event_actions.debounce,
);
} else {
queueEvents(events, socket);
Expand All @@ -782,7 +782,7 @@ export const useEventLoop = (
query,
asPath,
}))(router),
}))
})),
);
sentHydrate.current = true;
}
Expand Down Expand Up @@ -817,13 +817,9 @@ export const useEventLoop = (
};
}, []);

// Main event loop.
// Handle socket connect/disconnect.
useEffect(() => {
// Skip if the router is not ready.
if (!router.isReady) {
return;
}
// only use websockets if state is present
// only use websockets if state is present and backend is not disabled (reflex cloud).
if (Object.keys(initialState).length > 1 && !isBackendDisabled()) {
// Initialize the websocket connection.
if (!socket.current) {
Expand All @@ -832,16 +828,31 @@ export const useEventLoop = (
dispatch,
["websocket"],
setConnectErrors,
client_storage
client_storage,
);
}
(async () => {
// Process all outstanding events.
while (event_queue.length > 0 && !event_processing) {
await processEvent(socket.current);
}
})();
}

// Cleanup function.
return () => {
if (socket.current) {
socket.current.disconnect();
}
};
}, []);

// Main event loop.
useEffect(() => {
// Skip if the router is not ready.
if (!router.isReady || isBackendDisabled()) {
return;
}
(async () => {
// Process all outstanding events.
while (event_queue.length > 0 && !event_processing) {
await processEvent(socket.current);
}
})();
});

// localStorage event handling
Expand All @@ -865,7 +876,7 @@ export const useEventLoop = (
vars[storage_to_state_map[e.key]] = e.newValue;
const event = Event(
`${state_name}.reflex___state____update_vars_internal_state.update_vars_internal`,
{ vars: vars }
{ vars: vars },
);
addEvents([event], e);
}
Expand Down Expand Up @@ -958,7 +969,7 @@ export const getRefValues = (refs) => {
return refs.map((ref) =>
ref.current
? ref.current.value || ref.current.getAttribute("aria-valuenow")
: null
: null,
);
};

Expand Down
10 changes: 7 additions & 3 deletions reflex/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
from reflex.components.base.app_wrap import AppWrap
from reflex.components.base.error_boundary import ErrorBoundary
from reflex.components.base.fragment import Fragment
from reflex.components.base.strict_mode import StrictMode
from reflex.components.component import (
Component,
ComponentStyle,
Expand Down Expand Up @@ -956,6 +957,12 @@ def get_compilation_time() -> str:
# If a theme component was provided, wrap the app with it
app_wrappers[(20, "Theme")] = self.theme

# Get the env mode.
config = get_config()

if config.react_strict_mode:
app_wrappers[(200, "StrictMode")] = StrictMode.create()

should_compile = self._should_compile()

if not should_compile:
Expand Down Expand Up @@ -1001,9 +1008,6 @@ def get_compilation_time() -> str:

progress.advance(task)

# Get the env mode.
config = get_config()

# Store the compile results.
compile_results = []

Expand Down
10 changes: 10 additions & 0 deletions reflex/components/base/strict_mode.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""Module for the StrictMode component."""

from reflex.components.component import Component


class StrictMode(Component):
"""A React strict mode component to enable strict mode for its children."""

library = "react"
tag = "StrictMode"
57 changes: 57 additions & 0 deletions reflex/components/base/strict_mode.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
"""Stub file for reflex/components/base/strict_mode.py"""

# ------------------- DO NOT EDIT ----------------------
# This file was generated by `reflex/utils/pyi_generator.py`!
# ------------------------------------------------------
from typing import Any, Dict, Optional, Union, overload

from reflex.components.component import Component
from reflex.event import BASE_STATE, EventType
from reflex.style import Style
from reflex.vars.base import Var

class StrictMode(Component):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, Union[Var, Any]]] = None,
on_blur: Optional[EventType[[], BASE_STATE]] = None,
on_click: Optional[EventType[[], BASE_STATE]] = None,
on_context_menu: Optional[EventType[[], BASE_STATE]] = None,
on_double_click: Optional[EventType[[], BASE_STATE]] = None,
on_focus: Optional[EventType[[], BASE_STATE]] = None,
on_mount: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_down: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_enter: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_leave: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_move: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_out: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_over: Optional[EventType[[], BASE_STATE]] = None,
on_mouse_up: Optional[EventType[[], BASE_STATE]] = None,
on_scroll: Optional[EventType[[], BASE_STATE]] = None,
on_unmount: Optional[EventType[[], BASE_STATE]] = None,
**props,
) -> "StrictMode":
"""Create the component.

Args:
*children: The children of the component.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.

Returns:
The component.
"""
...
1 change: 0 additions & 1 deletion reflex/utils/prerequisites.py
Original file line number Diff line number Diff line change
Expand Up @@ -912,7 +912,6 @@ def _update_next_config(
next_config = {
"basePath": config.frontend_path or "",
"compress": config.next_compression,
"reactStrictMode": config.react_strict_mode,
"trailingSlash": True,
"staticPageGenerationTimeout": config.static_page_generation_timeout,
}
Expand Down
Loading