Skip to content

Instantly share code, notes, and snippets.

@mootinator
Last active September 26, 2023 23:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mootinator/b8eae6f8f2e32415802826172f0de10a to your computer and use it in GitHub Desktop.
Save mootinator/b8eae6f8f2e32415802826172f0de10a to your computer and use it in GitHub Desktop.
React.NET React 18 Shim
using React;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace React18Shim
{
public class React18Component : ReactComponent
{
public React18Component(IReactEnvironment environment, IReactSiteConfiguration configuration, IReactIdGenerator reactIdGenerator, string componentName, string containerId) : base(environment, configuration, reactIdGenerator, componentName, containerId)
{
}
/// <summary>
/// Renders the JavaScript required to initialise this component client-side. This will
/// initialise the React component, which includes attach event handlers to the
/// server-rendered HTML.
/// </summary>
/// <param name="writer">The <see cref="T:System.IO.TextWriter" /> to which the content is written</param>
/// <param name="waitForDOMContentLoad">Delays the component init until the page load event fires. Useful if the component script tags are located after the call to Html.ReactWithInit. </param>
/// <returns>JavaScript</returns>
public override void RenderJavaScript(TextWriter writer, bool waitForDOMContentLoad)
{
if (waitForDOMContentLoad)
{
writer.Write("window.addEventListener('DOMContentLoaded', function() {");
}
var hydrate = _configuration.UseServerSideRendering && !ClientOnly;
writer.Write(
!hydrate ? "ReactDOM.createRoot(" : "ReactDOM.hydrateRoot(");
writer.Write("document.getElementById(\"");
writer.Write(ContainerId);
if (hydrate)
{
writer.Write("\")");
writer.Write(", ");
WriteComponentInitialiser(writer);
writer.Write(")");
} else
{
writer.Write("\"))");
writer.Write(".render(");
WriteComponentInitialiser(writer);
writer.Write(")");
}
if (waitForDOMContentLoad)
{
writer.Write("});");
}
}
}
}
using React;
using System;
namespace React18Shim
{
public class React18Environment : ReactEnvironment
{
private readonly IReactIdGenerator _reactIdGenerator;
public React18Environment(IJavaScriptEngineFactory engineFactory, IReactSiteConfiguration config, ICache cache, IFileSystem fileSystem, IFileCacheHash fileCacheHash, IReactIdGenerator reactIdGenerator) : base(engineFactory, config, cache, fileSystem, fileCacheHash, reactIdGenerator)
{
_reactIdGenerator = reactIdGenerator;
}
/// <summary>
/// Creates an instance of the specified React JavaScript component.
/// </summary>
/// <typeparam name="T">Type of the props</typeparam>
/// <param name="componentName">Name of the component</param>
/// <param name="props">Props to use</param>
/// <param name="containerId">ID to use for the container HTML tag. Defaults to an auto-generated ID</param>
/// <param name="clientOnly">True if server-side rendering will be bypassed. Defaults to false.</param>
/// <param name="serverOnly">True if this component only should be rendered server-side. Defaults to false.</param>
/// <param name="skipLazyInit">Skip adding to components list, which is used during GetInitJavascript</param>
/// <returns>The component</returns>
public override IReactComponent CreateComponent<T>(string componentName, T props, string containerId = null, bool clientOnly = false, bool serverOnly = false, bool skipLazyInit = false)
{
if (!clientOnly)
{
EnsureUserScriptsLoaded();
}
var component = new React18Component(this, _config, _reactIdGenerator, componentName, containerId)
{
ClientOnly = clientOnly,
Props = props,
ServerOnly = serverOnly
};
if (!skipLazyInit)
{
_components.Add(component);
}
return component;
}
}
}
...
services.AddReact();
services.AddJsEngineSwitcher(options => options.DefaultEngineName = ChakraCoreJsEngine.EngineName).AddChakraCore();
...
app.UseReact(config =>
{
config
// .DisableServerSideRendering()
.SetLoadBabel(false)
.SetLoadReact(false)
.AddScriptWithoutTransform("~/js/polyfills.js")
.AddScriptWithoutTransform("~/js/server.js");
});
var wasregistered = React.AssemblyRegistration.Container.Unregister<IReactEnvironment>();
React.AssemblyRegistration.Container.Register<IReactEnvironment, React18Environment>().AsPerRequestSingleton();
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment