Skip to content

Commit af5e735

Browse files
committed
Merge branch 'master' of https://github.com/reactjs/React.NET
2 parents 05eb7cc + 60048e6 commit af5e735

File tree

6 files changed

+104
-37
lines changed

6 files changed

+104
-37
lines changed

site/jekyll/guides/server-side-rendering.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,26 @@ meaning your initial render will be super fast.
7272

7373
For a more in-depth example, take a look at the included sample application
7474
(**React.Samples.Mvc4**).
75+
76+
5 - Server-side only rendering
77+
78+
If there is no need to have a React application client side and you just want to use the server side rendering but without the React specific data attributes call `Html.React` and pass serverOnly parameter as true.
79+
80+
```csharp
81+
@Html.React("HelloWorld", new
82+
{
83+
name = "Daniel"
84+
}
85+
serverOnly:true)
86+
```
87+
88+
And the Html mark up will look like the one following which is a lot cleaner. In this case there is no need to load the React script or call the `Html.ReactInitJavaScript()` method.
89+
90+
```html
91+
<div id="react1">
92+
<div>
93+
<span>Hello </span>
94+
<span>Daniel</span>
95+
</div>
96+
</div>
97+
```

src/React.AspNet/HtmlHelperExtensions.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* All rights reserved.
44
*
55
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
6+
* LICENSE file in the root directory of this source tree. An additional grant
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

@@ -66,23 +66,25 @@ private static IReactEnvironment Environment
6666
/// <param name="props">Props to initialise the component with</param>
6767
/// <param name="htmlTag">HTML tag to wrap the component in. Defaults to &lt;div&gt;</param>
6868
/// <param name="containerId">ID to use for the container HTML tag. Defaults to an auto-generated ID</param>
69-
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
69+
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
70+
/// <param name="serverOnly">Skip rendering React specific data-attributes during server side rendering. Defaults to <c>false</c></param>
7071
/// <returns>The component's HTML</returns>
7172
public static IHtmlString React<T>(
7273
this IHtmlHelper htmlHelper,
7374
string componentName,
7475
T props,
7576
string htmlTag = null,
76-
string containerId = null,
77-
bool clientOnly = false
77+
string containerId = null,
78+
bool clientOnly = false,
79+
bool serverOnly = false
7880
)
7981
{
8082
var reactComponent = Environment.CreateComponent(componentName, props, containerId);
8183
if (!string.IsNullOrEmpty(htmlTag))
8284
{
8385
reactComponent.ContainerTag = htmlTag;
8486
}
85-
var result = reactComponent.RenderHtml(clientOnly);
87+
var result = reactComponent.RenderHtml(clientOnly, serverOnly);
8688
return new HtmlString(result);
8789
}
8890

@@ -97,15 +99,15 @@ public static IHtmlString React<T>(
9799
/// <param name="props">Props to initialise the component with</param>
98100
/// <param name="htmlTag">HTML tag to wrap the component in. Defaults to &lt;div&gt;</param>
99101
/// <param name="containerId">ID to use for the container HTML tag. Defaults to an auto-generated ID</param>
100-
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
102+
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
101103
/// <returns>The component's HTML</returns>
102104
public static IHtmlString ReactWithInit<T>(
103105
this IHtmlHelper htmlHelper,
104106
string componentName,
105107
T props,
106108
string htmlTag = null,
107-
string containerId = null,
108-
bool clientOnly = false
109+
string containerId = null,
110+
bool clientOnly = false
109111
)
110112
{
111113
var reactComponent = Environment.CreateComponent(componentName, props, containerId);
@@ -122,7 +124,7 @@ public static IHtmlString ReactWithInit<T>(
122124
}
123125

124126
/// <summary>
125-
/// Renders the JavaScript required to initialise all components client-side. This will
127+
/// Renders the JavaScript required to initialise all components client-side. This will
126128
/// attach event handlers to the server-rendered HTML.
127129
/// </summary>
128130
/// <returns>JavaScript for all components</returns>

src/React.Core/IReactComponent.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* All rights reserved.
44
*
55
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
6+
* LICENSE file in the root directory of this source tree. An additional grant
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

@@ -39,12 +39,13 @@ public interface IReactComponent
3939
/// return the rendered HTML.
4040
/// </summary>
4141
/// <param name="renderContainerOnly">Only renders component container. Used for client-side only rendering.</param>
42+
/// <param name="renderServerOnly">Only renders the common HTML mark up and not any React specific data attributes. Used for server-side only rendering.</param>
4243
/// <returns>HTML</returns>
43-
string RenderHtml(bool renderContainerOnly = false);
44+
string RenderHtml(bool renderContainerOnly = false, bool renderServerOnly = false);
4445

4546
/// <summary>
46-
/// Renders the JavaScript required to initialise this component client-side. This will
47-
/// initialise the React component, which includes attach event handlers to the
47+
/// Renders the JavaScript required to initialise this component client-side. This will
48+
/// initialise the React component, which includes attach event handlers to the
4849
/// server-rendered HTML.
4950
/// </summary>
5051
/// <returns>JavaScript</returns>

src/React.Core/ReactComponent.cs

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* All rights reserved.
44
*
55
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
6+
* LICENSE file in the root directory of this source tree. An additional grant
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

@@ -79,18 +79,20 @@ public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration con
7979
/// return the rendered HTML.
8080
/// </summary>
8181
/// <param name="renderContainerOnly">Only renders component container. Used for client-side only rendering.</param>
82+
/// <param name="renderServerOnly">Only renders the common HTML mark up and not any React specific data attributes. Used for server-side only rendering.</param>
8283
/// <returns>HTML</returns>
83-
public virtual string RenderHtml(bool renderContainerOnly = false)
84+
public virtual string RenderHtml(bool renderContainerOnly = false, bool renderServerOnly = false)
8485
{
8586
EnsureComponentExists();
8687
try
87-
{
88-
var html = string.Empty;
89-
if (!renderContainerOnly)
90-
{
91-
html = _environment.Execute<string>(
92-
string.Format("React.renderToString({0})", GetComponentInitialiser())
93-
);
88+
{
89+
var html = string.Empty;
90+
if (!renderContainerOnly)
91+
{
92+
var reactRenderCommand = renderServerOnly
93+
? string.Format("React.renderToStaticMarkup({0})", GetComponentInitialiser())
94+
: string.Format("React.renderToString({0})", GetComponentInitialiser());
95+
html = _environment.Execute<string>(reactRenderCommand);
9496
}
9597
return string.Format(
9698
"<{2} id=\"{0}\">{1}</{2}>",
@@ -111,8 +113,8 @@ public virtual string RenderHtml(bool renderContainerOnly = false)
111113
}
112114

113115
/// <summary>
114-
/// Renders the JavaScript required to initialise this component client-side. This will
115-
/// initialise the React component, which includes attach event handlers to the
116+
/// Renders the JavaScript required to initialise this component client-side. This will
117+
/// initialise the React component, which includes attach event handlers to the
116118
/// server-rendered HTML.
117119
/// </summary>
118120
/// <returns>JavaScript</returns>

src/React.Tests/Core/ReactComponentTest.cs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* All rights reserved.
44
*
55
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
6+
* LICENSE file in the root directory of this source tree. An additional grant
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

@@ -64,7 +64,7 @@ public void RenderHtmlShouldWrapComponentInDiv()
6464
}
6565

6666
[Test]
67-
public void RenderHtmlShouldNotRenderComponentHTML()
67+
public void RenderHtmlShouldNotRenderComponentHtml()
6868
{
6969
var environment = new Mock<IReactEnvironment>();
7070
environment.Setup(x => x.Execute<bool>("typeof Foo !== 'undefined'")).Returns(true);
@@ -82,6 +82,22 @@ public void RenderHtmlShouldNotRenderComponentHTML()
8282
environment.Verify(x => x.Execute(It.IsAny<string>()), Times.Never);
8383
}
8484

85+
[Test]
86+
public void RenderHtmlShouldNotRenderClientSideAttributes()
87+
{
88+
var environment = new Mock<IReactEnvironment>();
89+
environment.Setup(x => x.Execute<bool>("typeof Foo !== 'undefined'")).Returns(true);
90+
var config = new Mock<IReactSiteConfiguration>();
91+
92+
var component = new ReactComponent(environment.Object, config.Object, "Foo", "container")
93+
{
94+
Props = new { hello = "World" }
95+
};
96+
component.RenderHtml(renderServerOnly: true);
97+
98+
environment.Verify(x => x.Execute<string>(@"React.renderToStaticMarkup(React.createElement(Foo, {""hello"":""World""}))"));
99+
}
100+
85101
[Test]
86102
public void RenderHtmlShouldWrapComponentInCustomElement()
87103
{

src/React.Tests/Mvc/HtmlHelperExtensionsTests.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* All rights reserved.
44
*
55
* This source code is licensed under the BSD-style license found in the
6-
* LICENSE file in the root directory of this source tree. An additional grant
6+
* LICENSE file in the root directory of this source tree. An additional grant
77
* of patent rights can be found in the PATENTS file in the same directory.
88
*/
99

@@ -19,7 +19,7 @@ class HtmlHelperExtensionsTests
1919
{
2020
/// <summary>
2121
/// Creates a mock <see cref="IReactEnvironment"/> and registers it with the IoC container
22-
/// This is only required because <see cref="HtmlHelperExtensions"/> can not be
22+
/// This is only required because <see cref="HtmlHelperExtensions"/> can not be
2323
/// injected :(
2424
/// </summary>
2525
private Mock<IReactEnvironment> ConfigureMockEnvironment()
@@ -33,7 +33,7 @@ private Mock<IReactEnvironment> ConfigureMockEnvironment()
3333
public void ReactWithInitShouldReturnHtmlAndScript()
3434
{
3535
var component = new Mock<IReactComponent>();
36-
component.Setup(x => x.RenderHtml(false)).Returns("HTML");
36+
component.Setup(x => x.RenderHtml(false, false)).Returns("HTML");
3737
component.Setup(x => x.RenderJavaScript()).Returns("JS");
3838
var environment = ConfigureMockEnvironment();
3939
environment.Setup(x => x.CreateComponent(
@@ -44,12 +44,12 @@ public void ReactWithInitShouldReturnHtmlAndScript()
4444

4545
var result = HtmlHelperExtensions.ReactWithInit(
4646
htmlHelper: null,
47-
componentName: "ComponentName",
48-
props: new { },
47+
componentName: "ComponentName",
48+
props: new { },
4949
htmlTag: "span"
5050
);
5151
Assert.AreEqual(
52-
"HTML" + System.Environment.NewLine + "<script>JS</script>",
52+
"HTML" + System.Environment.NewLine + "<script>JS</script>",
5353
result.ToString()
5454
);
5555

@@ -59,7 +59,7 @@ public void ReactWithInitShouldReturnHtmlAndScript()
5959
public void ReactWithClientOnlyTrueShouldCallRenderHtmlWithTrue()
6060
{
6161
var component = new Mock<IReactComponent>();
62-
component.Setup(x => x.RenderHtml(true)).Returns("HTML");
62+
component.Setup(x => x.RenderHtml(true, true)).Returns("HTML");
6363
var environment = ConfigureMockEnvironment();
6464
environment.Setup(x => x.CreateComponent(
6565
"ComponentName",
@@ -69,12 +69,35 @@ public void ReactWithClientOnlyTrueShouldCallRenderHtmlWithTrue()
6969

7070
var result = HtmlHelperExtensions.React(
7171
htmlHelper: null,
72-
componentName: "ComponentName",
73-
props: new { },
72+
componentName: "ComponentName",
73+
props: new { },
7474
htmlTag: "span",
75-
clientOnly: true
75+
clientOnly: true,
76+
serverOnly: true
7677
);
77-
component.Verify(x => x.RenderHtml(It.Is<bool>(y => y == true)), Times.Once);
78+
component.Verify(x => x.RenderHtml(It.Is<bool>(y => y == true), It.Is<bool>(z => z == true)), Times.Once);
79+
}
80+
81+
[Test]
82+
public void ReactWithServerOnlyTrueShouldCallRenderHtmlWithTrue() {
83+
var component = new Mock<IReactComponent>();
84+
component.Setup(x => x.RenderHtml(true, true)).Returns("HTML");
85+
var environment = ConfigureMockEnvironment();
86+
environment.Setup(x => x.CreateComponent(
87+
"ComponentName",
88+
new { },
89+
null
90+
)).Returns(component.Object);
91+
92+
var result = HtmlHelperExtensions.React(
93+
htmlHelper: null,
94+
componentName: "ComponentName",
95+
props: new { },
96+
htmlTag: "span",
97+
clientOnly: true,
98+
serverOnly: true
99+
);
100+
component.Verify(x => x.RenderHtml(It.Is<bool>(y => y == true), It.Is<bool>(z => z == true)), Times.Once);
78101
}
79102
}
80103
}

0 commit comments

Comments
 (0)