Skip to content

Add HtmlHelperExtension flag to turn off server side rendering #103

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

Merged
merged 2 commits into from
Mar 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions src/React.AspNet/HtmlHelperExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,23 @@ private static IReactEnvironment Environment
/// <param name="props">Props to initialise the component with</param>
/// <param name="htmlTag">HTML tag to wrap the component in. Defaults to &lt;div&gt;</param>
/// <param name="containerId">ID to use for the container HTML tag. Defaults to an auto-generated ID</param>
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
/// <returns>The component's HTML</returns>
public static IHtmlString React<T>(
this IHtmlHelper htmlHelper,
string componentName,
T props,
string htmlTag = null,
string containerId = null
string containerId = null,
bool clientOnly = false
)
{
var reactComponent = Environment.CreateComponent(componentName, props, containerId);
if (!string.IsNullOrEmpty(htmlTag))
{
reactComponent.ContainerTag = htmlTag;
}
var result = reactComponent.RenderHtml();
var result = reactComponent.RenderHtml(clientOnly);
return new HtmlString(result);
}

Expand All @@ -95,21 +97,23 @@ public static IHtmlString React<T>(
/// <param name="props">Props to initialise the component with</param>
/// <param name="htmlTag">HTML tag to wrap the component in. Defaults to &lt;div&gt;</param>
/// <param name="containerId">ID to use for the container HTML tag. Defaults to an auto-generated ID</param>
/// <param name="clientOnly">Skip rendering server-side and only output client-side initialisation code. Defaults to <c>false</c></param>
/// <returns>The component's HTML</returns>
public static IHtmlString ReactWithInit<T>(
this IHtmlHelper htmlHelper,
string componentName,
T props,
string htmlTag = null,
string containerId = null
string containerId = null,
bool clientOnly = false
)
{
var reactComponent = Environment.CreateComponent(componentName, props, containerId);
if (!string.IsNullOrEmpty(htmlTag))
{
reactComponent.ContainerTag = htmlTag;
}
var html = reactComponent.RenderHtml();
var html = reactComponent.RenderHtml(clientOnly);
var script = new TagBuilder("script")
{
InnerHtml = reactComponent.RenderJavaScript()
Expand All @@ -132,4 +136,4 @@ public static IHtmlString ReactInitJavaScript(this IHtmlHelper htmlHelper)
return new HtmlString(tag.ToString());
}
}
}
}
5 changes: 3 additions & 2 deletions src/React.Core/IReactComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ public interface IReactComponent
/// Renders the HTML for this component. This will execute the component server-side and
/// return the rendered HTML.
/// </summary>
/// <param name="renderContainerOnly">Only renders component container. Used for client-side only rendering.</param>
/// <returns>HTML</returns>
string RenderHtml();
string RenderHtml(bool renderContainerOnly = false);

/// <summary>
/// Renders the JavaScript required to initialise this component client-side. This will
Expand All @@ -49,4 +50,4 @@ public interface IReactComponent
/// <returns>JavaScript</returns>
string RenderJavaScript();
}
}
}
13 changes: 9 additions & 4 deletions src/React.Core/ReactComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,20 @@ public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration con
/// Renders the HTML for this component. This will execute the component server-side and
/// return the rendered HTML.
/// </summary>
/// <param name="renderContainerOnly">Only renders component container. Used for client-side only rendering.</param>
/// <returns>HTML</returns>
public virtual string RenderHtml()
public virtual string RenderHtml(bool renderContainerOnly = false)
{
EnsureComponentExists();
try
{
var html = _environment.Execute<string>(
string.Format("React.renderToString({0})", GetComponentInitialiser())
{
var html = string.Empty;
if (!renderContainerOnly)
{
html = _environment.Execute<string>(
string.Format("React.renderToString({0})", GetComponentInitialiser())
);
}
return string.Format(
"<{2} id=\"{0}\">{1}</{2}>",
ContainerId,
Expand Down
19 changes: 19 additions & 0 deletions src/React.Tests/Core/ReactComponentTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,25 @@ public void RenderHtmlShouldWrapComponentInDiv()
Assert.AreEqual(@"<div id=""container"">[HTML]</div>", result);
}

[Test]
public void RenderHtmlShouldNotRenderComponentHTML()
{
var environment = new Mock<IReactEnvironment>();
environment.Setup(x => x.Execute<bool>("typeof Foo !== 'undefined'")).Returns(true);
environment.Setup(x => x.Execute<string>(@"React.renderToString(React.createElement(Foo, {""hello"":""World""}))"))
.Returns("[HTML]");
var config = new Mock<IReactSiteConfiguration>();

var component = new ReactComponent(environment.Object, config.Object, "Foo", "container")
{
Props = new { hello = "World" }
};
var result = component.RenderHtml(renderContainerOnly: true);

Assert.AreEqual(@"<div id=""container""></div>", result);
environment.Verify(x => x.Execute(It.IsAny<string>()), Times.Never);
}

[Test]
public void RenderHtmlShouldWrapComponentInCustomElement()
{
Expand Down
24 changes: 23 additions & 1 deletion src/React.Tests/Mvc/HtmlHelperExtensionsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private Mock<IReactEnvironment> ConfigureMockEnvironment()
public void ReactWithInitShouldReturnHtmlAndScript()
{
var component = new Mock<IReactComponent>();
component.Setup(x => x.RenderHtml()).Returns("HTML");
component.Setup(x => x.RenderHtml(false)).Returns("HTML");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep this as RenderHtml() since false is the default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't change this, VS complains: "An expression tree may not contain a call or invocation that uses optional arguments".

component.Setup(x => x.RenderJavaScript()).Returns("JS");
var environment = ConfigureMockEnvironment();
environment.Setup(x => x.CreateComponent(
Expand All @@ -54,5 +54,27 @@ public void ReactWithInitShouldReturnHtmlAndScript()
);

}

[Test]
public void ReactWithClientOnlyTrueShouldCallRenderHtmlWithTrue()
{
var component = new Mock<IReactComponent>();
component.Setup(x => x.RenderHtml(true)).Returns("HTML");
var environment = ConfigureMockEnvironment();
environment.Setup(x => x.CreateComponent(
"ComponentName",
new {},
null
)).Returns(component.Object);

var result = HtmlHelperExtensions.React(
htmlHelper: null,
componentName: "ComponentName",
props: new { },
htmlTag: "span",
clientOnly: true
);
component.Verify(x => x.RenderHtml(It.Is<bool>(y => y == true)), Times.Once);
}
}
}