Skip to content

Commit

Permalink
Add json props to html as script tag. Hydrate based of props from scr…
Browse files Browse the repository at this point in the history
…ipt tag.
  • Loading branch information
Pawel Markowicz committed Apr 14, 2023
1 parent 47d17b7 commit 520c96d
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 26 deletions.
6 changes: 5 additions & 1 deletion Forte.React.AspNetCore/React/Component.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ namespace Forte.React.AspNetCore.React;

internal class Component
{

public string Name { get; }
public object Props { get; }
public string ContainerId { get; } = Guid.NewGuid().ToString("n")[..8];
public string ContainerId { get; }
public string JsonContainerId { get; }

public Component(string name, object props)
{
Name = name;
Props = props;
ContainerId = Guid.NewGuid().ToString("n")[..8];
JsonContainerId = ContainerId + "-json";
}
}
24 changes: 9 additions & 15 deletions Forte.React.AspNetCore/React/ReactService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,17 @@ public class ReactService : IReactService
private readonly ReactConfiguration _config;
private const string RenderToStringCacheIdentifier = nameof(RenderToStringAsync);

private readonly JsonSerializerOptions _serializeOptions;

public static IReactService Create(IServiceProvider serviceProvider)
{
return new ReactService(
serviceProvider.GetRequiredService<INodeJSService>(),
serviceProvider.GetRequiredService<ReactConfiguration>(),
serviceProvider.GetRequiredService<IOptions<ReactJsonSerializerOptions>>());
serviceProvider.GetRequiredService<ReactConfiguration>());
}

private ReactService(INodeJSService nodeJsService, ReactConfiguration config,
IOptions<ReactJsonSerializerOptions> serializeOptions)
private ReactService(INodeJSService nodeJsService, ReactConfiguration config)
{
_nodeJsService = nodeJsService;
_config = config;
_serializeOptions = serializeOptions.Value.Options;
}

public async Task<string> RenderToStringAsync(string componentName, object props)
Expand All @@ -53,7 +48,7 @@ public async Task<string> RenderToStringAsync(string componentName, object props
return WrapRenderedStringComponent(string.Empty, component);
}

var args = new[] { componentName, props, _config.ScriptUrls };
var args = new[] { componentName, component.JsonContainerId, props, _config.ScriptUrls };

var (success, cachedResult) =
await _nodeJsService.TryInvokeFromCacheAsync<string>(RenderToStringCacheIdentifier, args: args);
Expand All @@ -73,7 +68,8 @@ Stream ModuleFactory()
$"Can not get manifest resource stream with name - {renderToStringScriptManifestName}");
}

var result = await _nodeJsService.InvokeFromStreamAsync<string>(ModuleFactory,
await using var stream = ModuleFactory();
var result = await _nodeJsService.InvokeFromStreamAsync<string>(stream,
RenderToStringCacheIdentifier,
args: args);

Expand All @@ -99,14 +95,12 @@ public string GetInitJavascript()
}

private static string GetElementById(string containerId)
{
return $"document.getElementById(\"{containerId}\")";
}
=> $"document.getElementById(\"{containerId}\")";


private string CreateElement(Component component)
{
return $"React.createElement({component.Name}, {JsonSerializer.Serialize(component.Props, _serializeOptions)})";
}
=>
$"React.createElement({component.Name}, JSON.parse(document.getElementById(\"{component.JsonContainerId}\").textContent))";


private string Render(Component component)
Expand Down
31 changes: 21 additions & 10 deletions Forte.React.AspNetCore/renderToString.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
module.exports = (callback, componentName, props = {}, scriptFiles) => {
scriptFiles.forEach((scriptFile) => { require(scriptFile) });
module.exports = (
callback,
componentName,
jsonContainerId,
props = {},
scriptFiles
) => {
scriptFiles.forEach((scriptFile) => {
require(scriptFile);
});
const component = global[componentName];

const component = global[componentName];
const ReactDOMServer = global["ReactDOMServer"];
const React = global["React"];
const element = React.createElement(component, props);

const ReactDOMServer = global["ReactDOMServer"];
const React = global["React"];
const element = React.createElement(component, props);
const componentHtml = `${ReactDOMServer.renderToString(element)}`;
const jsonHtml = `<script id="${jsonContainerId}" type="json">${JSON.stringify(
props
)}</script>`;
const result = componentHtml + jsonHtml;

const result = ReactDOMServer.renderToString(element);

callback(null /* error */, result /* result */);
}
callback(null /* error */, result /* result */);
};

0 comments on commit 520c96d

Please sign in to comment.