Skip to content

Commit 04f3d35

Browse files
AbanoubGhadbanExample User
andauthored
Add example for returning component from async render function (#1829)
* add examples make renderer runnable on one process Modify example views to pass props to components and add integration tests for async rendering functionality. Revert "make renderer runnable on one process" This reverts commit 91efa37a665f836b05a116e6548ef809d956a67c. Update Gemfile and package.json to use the master branch of react_on_rails Update component source paths and improve menu link labels for clarity revert changes to react on rails dependency * Add 'use client' directive to AsyncRenderFunction components for client-side rendering support --------- Co-authored-by: Example User <example@example.com>
1 parent fbbb8fc commit 04f3d35

9 files changed

+107
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<h1>Async Render Function Returns Component</h1>
2+
<p>
3+
This example demonstrates a component that returns a React component from an async function.
4+
</p>
5+
6+
<%= react_component("AsyncRenderFunctionReturnsComponent", props: { hello: "world" }, prerender: true, trace: true) %>
7+
8+
<hr/>
9+
<h2>Details</h2>
10+
<p>
11+
Component source: spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsComponent.server.jsx
12+
</p>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<h1>Async Render Function Returns String</h1>
2+
<p>
3+
This example demonstrates a component that returns a string from an async function.
4+
</p>
5+
6+
<%= react_component("AsyncRenderFunctionReturnsString", props: { hello: "world" }, prerender: true, trace: true) %>
7+
8+
<hr/>
9+
<h2>Details</h2>
10+
<p>
11+
Component source: spec/dummy/client/app/ror-auto-load-components/AsyncRenderFunctionReturnsString.server.jsx
12+
</p>

react_on_rails_pro/spec/dummy/app/views/shared/_menu.erb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ end
5555
<li>
5656
<%= link_to("Console Logs in Async Server", console_logs_in_async_server_path, class: cp(console_logs_in_async_server_path)) %>
5757
</li>
58+
<li>
59+
<%= link_to("Async Render Function Returns a String", async_render_function_returns_string_path, class: cp(async_render_function_returns_string_path)) %>
60+
</li>
61+
<li>
62+
<%= link_to("Async Render Function Returns a Component", async_render_function_returns_component_path, class: cp(async_render_function_returns_component_path)) %>
63+
</li>
5864
</ul>
5965

6066
<h2 class="text-red-700 text-2xl mt-5">
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use client';
2+
3+
// Top level component for simple client side only rendering
4+
import React from 'react';
5+
6+
import EchoProps from '../components/EchoProps';
7+
8+
export default (props) => <EchoProps {...props} />;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
'use client';
2+
3+
// Top level component for simple client side only rendering
4+
import React from 'react';
5+
import EchoProps from '../components/EchoProps';
6+
7+
/*
8+
* Export an async function that takes the props and returns a promise that resolves to a React component.
9+
*
10+
* Note, this is a fictional example, as you'd only use a Render-Function if you wanted to run
11+
* some extra code, such as setting up Redux and React Router.
12+
*
13+
*/
14+
export default async (props, _railsContext) => {
15+
await Promise.resolve();
16+
return () => <EchoProps {...props} />;
17+
};
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use client';
2+
3+
// Top level component for simple client side only rendering
4+
import React from 'react';
5+
6+
import EchoProps from '../components/EchoProps';
7+
8+
export default (props) => <EchoProps {...props} />;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use client';
2+
3+
// Top level component for simple client side only rendering
4+
import React from 'react';
5+
import { renderToString } from 'react-dom/server';
6+
import EchoProps from '../components/EchoProps';
7+
8+
/*
9+
* Export an async function that takes the props and returns a promise that resolves to the rendered HTML string.
10+
*
11+
* Note, this is a fictional example, as you'd only use a Render-Function if you wanted to run
12+
* some extra code, such as setting up Redux and React Router.
13+
*
14+
* And the use of renderToString would probably be done with React Router v4
15+
*
16+
*/
17+
export default async (props, _railsContext) => {
18+
const renderedHtml = await Promise.resolve(renderToString(<EchoProps {...props} />));
19+
return renderedHtml;
20+
};

react_on_rails_pro/spec/dummy/config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
as: :async_on_server_sync_on_client_client_render
3535
get "server_router/(*all)" => "pages#server_router", as: :server_router
3636
get "server_router_client_render/(*all)" => "pages#server_router_client_render", as: :server_router_client_render
37+
get "async_render_function_returns_string" => "pages#async_render_function_returns_string"
38+
get "async_render_function_returns_component" => "pages#async_render_function_returns_component"
3739
rsc_payload_route controller: "pages"
3840

3941
# routes copied over from react on rails

react_on_rails_pro/spec/dummy/spec/system/integration_spec.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,28 @@ def change_text_expect_dom_selector(dom_selector, expect_no_change: false)
217217
end
218218
end
219219

220+
describe "async render function returns string", :js do
221+
subject { page }
222+
223+
before { visit "/async_render_function_returns_string" }
224+
225+
it "renders the string returned from the async render function" do
226+
expect(page).to have_text 'Props: {"hello":"world"}'
227+
expect(page.html).to include("[SERVER] RENDERED AsyncRenderFunctionReturnsString to dom node with id")
228+
end
229+
end
230+
231+
describe "async render function returns component", :js do
232+
subject { page }
233+
234+
before { visit "/async_render_function_returns_component" }
235+
236+
it "renders the component returned from the async render function" do
237+
expect(page).to have_text 'Props: {"hello":"world"}'
238+
expect(page.html).to include("[SERVER] RENDERED AsyncRenderFunctionReturnsComponent to dom node with id")
239+
end
240+
end
241+
220242
describe "Manual client hydration", :js, type: :system do
221243
before { visit "/xhr_refresh" }
222244

0 commit comments

Comments
 (0)