Class: ReactOnRailsPro::AsyncPropsEmitter
- Inherits:
-
Object
- Object
- ReactOnRailsPro::AsyncPropsEmitter
- Defined in:
- lib/react_on_rails_pro/async_props_emitter.rb
Overview
Emitter class for sending async props incrementally during streaming render. Used by stream_react_component_with_async_props helper.
PROTOCOL:
Each call to emit.call(prop_name, value) sends an NDJSON line to the Node renderer:
{"bundleTimestamp": "abc123", "updateChunk": "(function(){...})()"}
The updateChunk JavaScript accesses the AsyncPropsManager via sharedExecutionContext and resolves the promise for that prop, allowing React to continue rendering.
WHY NOT USE GLOBAL VARIABLES? Global variables in Node.js VM persist across requests, causing data leakage. sharedExecutionContext is scoped to a single HTTP request (ExecutionContext).
PULL MODE:
When pull_enabled is true, React components can request props lazily via
getProp(). Those requests arrive as propRequest chunks on the response stream.
pull_requests exposes an Async::Queue that yields prop names as they arrive.
The user's block can dequeue and resolve them dynamically.
Constant Summary collapse
- SANITIZED_REJECTION_REASON =
"Async prop rejected by server"
Instance Attribute Summary collapse
-
#pull_requests ⇒ Object
readonly
Returns the value of attribute pull_requests.
Instance Method Summary collapse
-
#call(prop_name, prop_value) ⇒ Object
Sends an async prop to the Node renderer.
-
#end_stream_chunk ⇒ Object
Generates the chunk that should be executed when the request stream closes.
-
#initialize(bundle_timestamp, request_stream, pull_enabled: false) ⇒ AsyncPropsEmitter
constructor
A new instance of AsyncPropsEmitter.
-
#reject(prop_name, reason) ⇒ Object
Rejects an async prop on the Node side so React can show an error boundary.
-
#render_complete! ⇒ Object
Called by stream_request when the response stream signals render complete.
Constructor Details
#initialize(bundle_timestamp, request_stream, pull_enabled: false) ⇒ AsyncPropsEmitter
Returns a new instance of AsyncPropsEmitter.
55 56 57 58 59 60 61 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 55 def initialize(, request_stream, pull_enabled: false) @bundle_timestamp = @request_stream = request_stream @pushed_props = Set.new @pull_enabled = pull_enabled @pull_requests = PullRequestQueue.new(@pushed_props) if pull_enabled end |
Instance Attribute Details
#pull_requests ⇒ Object (readonly)
Returns the value of attribute pull_requests.
53 54 55 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 53 def pull_requests @pull_requests end |
Instance Method Details
#call(prop_name, prop_value) ⇒ Object
Sends an async prop to the Node renderer. The prop value is JSON-serialized and sent as an NDJSON line. On the Node side, this triggers asyncPropsManager.setProp(propName, value).
66 67 68 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 66 def call(prop_name, prop_value) write_settled_chunk(prop_name, action: "send") { generate_update_chunk(prop_name, prop_value) } end |
#end_stream_chunk ⇒ Object
Generates the chunk that should be executed when the request stream closes. This tells the asyncPropsManager to end the stream.
79 80 81 82 83 84 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 79 def end_stream_chunk { bundleTimestamp: @bundle_timestamp, updateChunk: generate_end_stream_js } end |
#reject(prop_name, reason) ⇒ Object
Rejects an async prop on the Node side so React can show an error boundary.
71 72 73 74 75 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 71 def reject(prop_name, reason) # Once the reject chunk is written, Ruby treats the prop as settled too. # That keeps duplicate pull requests filtered even if the JS manager is recreated. write_settled_chunk(prop_name, action: "reject") { generate_reject_chunk(prop_name, reason) } end |
#render_complete! ⇒ Object
Called by stream_request when the response stream signals render complete. Closes the pull_requests queue so dequeue returns nil.
88 89 90 |
# File 'lib/react_on_rails_pro/async_props_emitter.rb', line 88 def render_complete! @pull_requests&.close end |