From d0fcea19e43f2274ed0960d2107f3f3dfd438190 Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Thu, 10 May 2018 12:42:34 -0700 Subject: [PATCH 1/9] Added ClientOnly property to ReactComponent --- src/React.Core/ReactEnvironment.cs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/React.Core/ReactEnvironment.cs b/src/React.Core/ReactEnvironment.cs index 1f9ebec9f..4d1922d4f 100644 --- a/src/React.Core/ReactEnvironment.cs +++ b/src/React.Core/ReactEnvironment.cs @@ -3,7 +3,7 @@ * All rights reserved. * * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant + * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ @@ -22,7 +22,7 @@ namespace React { /// - /// Request-specific ReactJS.NET environment. This is unique to the individual request and is + /// Request-specific ReactJS.NET environment. This is unique to the individual request and is /// not shared. /// public class ReactEnvironment : IReactEnvironment, IDisposable @@ -70,7 +70,7 @@ public class ReactEnvironment : IReactEnvironment, IDisposable /// protected readonly Lazy _version = new Lazy(GetVersion); /// - /// Contains an engine acquired from a pool of engines. Only used if + /// Contains an engine acquired from a pool of engines. Only used if /// is enabled. /// protected Lazy _engineFromPool; @@ -141,7 +141,7 @@ IReactIdGenerator reactIdGenerator _fileSystem = fileSystem; _fileCacheHash = fileCacheHash; _reactIdGenerator = reactIdGenerator; - _babelTransformer = new Lazy(() => + _babelTransformer = new Lazy(() => new Babel(this, _cache, _fileSystem, _fileCacheHash, _config) ); _engineFromPool = new Lazy(() => _engineFactory.GetEngine()); @@ -302,8 +302,9 @@ public virtual IReactComponent CreateComponent(string componentName, T props, EnsureUserScriptsLoaded(); } - var component = new ReactComponent(this, _config, _reactIdGenerator, componentName, containerId) + var component = new ReactComponent(this, _config, _reactIdGenerator, clientOnly, componentName, containerId) { + ClientOnly = clientOnly, Props = props, ServerOnly = serverOnly }; @@ -329,7 +330,7 @@ public virtual IReactComponent CreateComponent(IReactComponent component, bool c } /// - /// Renders the JavaScript required to initialise all components client-side. This will + /// Renders the JavaScript required to initialise all components client-side. This will /// attach event handlers to the server-rendered HTML. /// /// True if server-side rendering will be bypassed. Defaults to false. @@ -344,7 +345,7 @@ public virtual string GetInitJavaScript(bool clientOnly = false) } /// - /// Renders the JavaScript required to initialise all components client-side. This will + /// Renders the JavaScript required to initialise all components client-side. This will /// attach event handlers to the server-rendered HTML. /// /// The to which the content is written @@ -371,12 +372,12 @@ public virtual void GetInitJavaScript(TextWriter writer, bool clientOnly = false /// /// Attempts to execute the provided JavaScript code using a non-pooled JavaScript engine (ie. - /// creates a new JS engine per-thread). This is because Babel uses a LOT of memory, so we + /// creates a new JS engine per-thread). This is because Babel uses a LOT of memory, so we /// should completely dispose any engines that have loaded Babel in order to conserve memory. - /// + /// /// If an exception is thrown, retries the execution using a new thread (and hence a new engine) /// with a larger maximum stack size. - /// This is required because JSXTransformer uses a huge stack which ends up being larger + /// This is required because JSXTransformer uses a huge stack which ends up being larger /// than what ASP.NET allows by default (256 KB). /// /// Type to return from JavaScript call @@ -396,7 +397,7 @@ public virtual T ExecuteWithBabel(string function, params object[] args) catch (Exception) { - // Assume the exception MAY be an "out of stack space" error. Try running the code + // Assume the exception MAY be an "out of stack space" error. Try running the code // in a different thread with larger stack. If the same exception occurs, we know // it wasn't a stack space issue. T result = default(T); From e1b503afb38035a036c226804c97b0e3aaf0b839 Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Sun, 13 May 2018 12:02:16 -0700 Subject: [PATCH 2/9] added conditional to RenderJavascript to decide between ReactDOM.render vs ReactDOM.hydrate --- src/React.Core/ReactComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/React.Core/ReactComponent.cs b/src/React.Core/ReactComponent.cs index 376315779..04a3c7149 100644 --- a/src/React.Core/ReactComponent.cs +++ b/src/React.Core/ReactComponent.cs @@ -233,7 +233,7 @@ public virtual string RenderJavaScript() /// JavaScript public virtual void RenderJavaScript(TextWriter writer) { - writer.Write("ReactDOM.hydrate("); + ClientOnly ? writer.Write("ReactDOM.render(") : writer.Write("ReactDOM.hydrate("); WriteComponentInitialiser(writer); writer.Write(", document.getElementById(\""); writer.Write(ContainerId); From e13331c0c14cbc0471f911991fdc61722381eb3e Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Sun, 13 May 2018 12:07:14 -0700 Subject: [PATCH 3/9] Added 2 tests to check if correct method ReactDOM.render or ReactDOM.hydrate used when toggling clientOnly parameter in ReactComponent --- tests/React.Tests/Core/ReactComponentTest.cs | 42 +++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/tests/React.Tests/Core/ReactComponentTest.cs b/tests/React.Tests/Core/ReactComponentTest.cs index 735436b54..06ece7d75 100644 --- a/tests/React.Tests/Core/ReactComponentTest.cs +++ b/tests/React.Tests/Core/ReactComponentTest.cs @@ -213,6 +213,46 @@ public void RenderJavaScriptShouldCallRenderComponent() ); } + [Fact] + public void RenderJavaScriptShouldCallRenderComponentWithReactDOMRender() + { + var environment = new Mock(); + var clientOnly = true; + var config = new Mock(); + var reactIdGenerator = new Mock(); + + var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, clientOnly, "Foo", "container") + { + Props = new { hello = "World" } + }; + var result = component.RenderJavaScript(); + + Assert.Equal( + @"ReactDOM.hydrate(React.createElement(Foo, {""hello"":""World""}), document.getElementById(""container""))", + result + ); + } + + [Fact] + public void RenderJavaScriptShouldCallRenderComponentwithReactDOMHydrate() + { + var environment = new Mock(); + var clientOnly = false; + var config = new Mock(); + var reactIdGenerator = new Mock(); + + var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, clientOnly, "Foo", "container") + { + Props = new { hello = "World" } + }; + var result = component.RenderJavaScript(); + + Assert.Equal( + @"ReactDOM.hydrate(React.createElement(Foo, {""hello"":""World""}), document.getElementById(""container""))", + result + ); + } + [Theory] [InlineData("Foo", true)] [InlineData("Foo.Bar", true)] @@ -284,7 +324,7 @@ public void ExceptionThrownIsHandled() Action customHandler = (ex, name, id) => customHandlerInvoked = true; component.RenderHtml(exceptionHandler: customHandler); Assert.True(customHandlerInvoked); - + // Custom exception handler set Exception caughtException = null; config.Setup(x => x.ExceptionHandler).Returns((ex, name, id) => caughtException = ex); From 02ce1182cb4190d5368e03374577672fe2f6c2e5 Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Tue, 5 Jun 2018 19:41:18 -0700 Subject: [PATCH 4/9] Made available ClientOnly and correctly implemented ternary operator using Write --- src/React.Core/ReactComponent.cs | 5 +++-- src/React.Core/ReactEnvironment.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/React.Core/ReactComponent.cs b/src/React.Core/ReactComponent.cs index 04a3c7149..3105dbd4c 100644 --- a/src/React.Core/ReactComponent.cs +++ b/src/React.Core/ReactComponent.cs @@ -95,6 +95,7 @@ public object Props _configuration.JsonSerializerSettings); } } + public bool ClientOnly { get; set; } /// /// Initializes a new instance of the class. @@ -104,7 +105,7 @@ public object Props /// React Id generator. /// Name of the component. /// The ID of the container DIV for this component - public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId) + public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId, boolean clientOnly) { EnsureComponentNameValid(componentName); _environment = environment; @@ -233,7 +234,7 @@ public virtual string RenderJavaScript() /// JavaScript public virtual void RenderJavaScript(TextWriter writer) { - ClientOnly ? writer.Write("ReactDOM.render(") : writer.Write("ReactDOM.hydrate("); + writer.Write(ClientOnly ? "ReactDOM.render(" : "ReactDOM.hydrate("); WriteComponentInitialiser(writer); writer.Write(", document.getElementById(\""); writer.Write(ContainerId); diff --git a/src/React.Core/ReactEnvironment.cs b/src/React.Core/ReactEnvironment.cs index 4d1922d4f..b085e9f59 100644 --- a/src/React.Core/ReactEnvironment.cs +++ b/src/React.Core/ReactEnvironment.cs @@ -302,7 +302,7 @@ public virtual IReactComponent CreateComponent(string componentName, T props, EnsureUserScriptsLoaded(); } - var component = new ReactComponent(this, _config, _reactIdGenerator, clientOnly, componentName, containerId) + var component = new ReactComponent(this, _config, _reactIdGenerator, componentName, containerId) { ClientOnly = clientOnly, Props = props, From f319c8fb9533551cf4429e8c116fb7c84caa86ea Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Tue, 5 Jun 2018 19:49:11 -0700 Subject: [PATCH 5/9] Removed redundant call to ClientOnly --- src/React.Core/ReactComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/React.Core/ReactComponent.cs b/src/React.Core/ReactComponent.cs index 3105dbd4c..1d088701d 100644 --- a/src/React.Core/ReactComponent.cs +++ b/src/React.Core/ReactComponent.cs @@ -105,7 +105,7 @@ public object Props /// React Id generator. /// Name of the component. /// The ID of the container DIV for this component - public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId, boolean clientOnly) + public ReactComponent(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId) { EnsureComponentNameValid(componentName); _environment = environment; From 49c013f9fbe0dd08fd54e44c11a5d2a6c1bad0e8 Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Tue, 5 Jun 2018 19:59:21 -0700 Subject: [PATCH 6/9] Changed tests to correctly take in ClientOnly --- tests/React.Tests/Core/ReactComponentTest.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/React.Tests/Core/ReactComponentTest.cs b/tests/React.Tests/Core/ReactComponentTest.cs index 06ece7d75..ae6106184 100644 --- a/tests/React.Tests/Core/ReactComponentTest.cs +++ b/tests/React.Tests/Core/ReactComponentTest.cs @@ -221,8 +221,9 @@ public void RenderJavaScriptShouldCallRenderComponentWithReactDOMRender() var config = new Mock(); var reactIdGenerator = new Mock(); - var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, clientOnly, "Foo", "container") + var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, "Foo", "container") { + ClientOnly = true; Props = new { hello = "World" } }; var result = component.RenderJavaScript(); @@ -241,8 +242,9 @@ public void RenderJavaScriptShouldCallRenderComponentwithReactDOMHydrate() var config = new Mock(); var reactIdGenerator = new Mock(); - var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, clientOnly, "Foo", "container") + var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, "Foo", "container") { + ClientOnly = false; Props = new { hello = "World" } }; var result = component.RenderJavaScript(); From ccf55bcc5f182ee5765d71c6595234c8122835bc Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Tue, 5 Jun 2018 20:10:19 -0700 Subject: [PATCH 7/9] Changed incorrect punctuation in test file --- tests/React.Tests/Core/ReactComponentTest.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/React.Tests/Core/ReactComponentTest.cs b/tests/React.Tests/Core/ReactComponentTest.cs index ae6106184..7da51631e 100644 --- a/tests/React.Tests/Core/ReactComponentTest.cs +++ b/tests/React.Tests/Core/ReactComponentTest.cs @@ -217,13 +217,12 @@ public void RenderJavaScriptShouldCallRenderComponent() public void RenderJavaScriptShouldCallRenderComponentWithReactDOMRender() { var environment = new Mock(); - var clientOnly = true; var config = new Mock(); var reactIdGenerator = new Mock(); var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, "Foo", "container") { - ClientOnly = true; + ClientOnly = true, Props = new { hello = "World" } }; var result = component.RenderJavaScript(); @@ -238,13 +237,12 @@ public void RenderJavaScriptShouldCallRenderComponentWithReactDOMRender() public void RenderJavaScriptShouldCallRenderComponentwithReactDOMHydrate() { var environment = new Mock(); - var clientOnly = false; var config = new Mock(); var reactIdGenerator = new Mock(); var component = new ReactComponent(environment.Object, config.Object, reactIdGenerator.Object, "Foo", "container") { - ClientOnly = false; + ClientOnly = false, Props = new { hello = "World" } }; var result = component.RenderJavaScript(); From dfdd90ba626aae4d46422663f63e38933cfa833e Mon Sep 17 00:00:00 2001 From: Suhail Ansari Date: Tue, 5 Jun 2018 20:16:31 -0700 Subject: [PATCH 8/9] Corrected tests to use render if true --- tests/React.Tests/Core/ReactComponentTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/React.Tests/Core/ReactComponentTest.cs b/tests/React.Tests/Core/ReactComponentTest.cs index 7da51631e..dbf6049cf 100644 --- a/tests/React.Tests/Core/ReactComponentTest.cs +++ b/tests/React.Tests/Core/ReactComponentTest.cs @@ -228,7 +228,7 @@ public void RenderJavaScriptShouldCallRenderComponentWithReactDOMRender() var result = component.RenderJavaScript(); Assert.Equal( - @"ReactDOM.hydrate(React.createElement(Foo, {""hello"":""World""}), document.getElementById(""container""))", + @"ReactDOM.render(React.createElement(Foo, {""hello"":""World""}), document.getElementById(""container""))", result ); } From 67ad5149cb45f61db16cf335f12e02d983579102 Mon Sep 17 00:00:00 2001 From: Dustin Masters Date: Sun, 10 Jun 2018 15:08:54 -0700 Subject: [PATCH 9/9] Update examples to react 16.4 --- src/React.Sample.Cassette/Views/Home/Index.cshtml | 4 ++-- src/React.Sample.CoreMvc/Views/Home/Index.cshtml | 4 ++-- src/React.Sample.Mvc4/Views/Home/Index.cshtml | 4 ++-- src/React.Sample.Owin/Content/Index.html | 4 ++-- src/React.Sample.Webpack/Views/Home/Index.cshtml | 4 ++-- tutorial-code/Views/Home/Index.cshtml | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/React.Sample.Cassette/Views/Home/Index.cshtml b/src/React.Sample.Cassette/Views/Home/Index.cshtml index 5de9a00d4..80974a81f 100644 --- a/src/React.Sample.Cassette/Views/Home/Index.cshtml +++ b/src/React.Sample.Cassette/Views/Home/Index.cshtml @@ -20,8 +20,8 @@ @Html.React("CommentsBox", new { initialComments = Model.Comments }) - - + + @Bundles.RenderScripts() diff --git a/src/React.Sample.CoreMvc/Views/Home/Index.cshtml b/src/React.Sample.CoreMvc/Views/Home/Index.cshtml index 6f939ad17..feaaa3a3c 100644 --- a/src/React.Sample.CoreMvc/Views/Home/Index.cshtml +++ b/src/React.Sample.CoreMvc/Views/Home/Index.cshtml @@ -17,8 +17,8 @@ @Html.React("CommentsBox", new { initialComments = Model.Comments, ThrowRenderError = Model.ThrowRenderError }) - - + + diff --git a/src/React.Sample.Mvc4/Views/Home/Index.cshtml b/src/React.Sample.Mvc4/Views/Home/Index.cshtml index 70eb54233..cc0b53f03 100644 --- a/src/React.Sample.Mvc4/Views/Home/Index.cshtml +++ b/src/React.Sample.Mvc4/Views/Home/Index.cshtml @@ -17,8 +17,8 @@ @Html.React("CommentsBox", new { initialComments = Model.Comments, page = Model.Page }) - - + + @Scripts.Render("~/bundles/main") diff --git a/src/React.Sample.Owin/Content/Index.html b/src/React.Sample.Owin/Content/Index.html index c5f413438..5cb251d6d 100644 --- a/src/React.Sample.Owin/Content/Index.html +++ b/src/React.Sample.Owin/Content/Index.html @@ -8,8 +8,8 @@
- - + + - + + diff --git a/tutorial-code/Views/Home/Index.cshtml b/tutorial-code/Views/Home/Index.cshtml index 8260b7f9b..168719213 100644 --- a/tutorial-code/Views/Home/Index.cshtml +++ b/tutorial-code/Views/Home/Index.cshtml @@ -14,8 +14,8 @@ submitUrl = Url.Action("AddComment"), pollInterval = 2000, }) - - + +