Material UI
KennyLMQ opened this issue · 6 comments
This is a request for help.
I'm trying to use Material UI with React.NET (webpack).
During refresh, there is flickering and the styling loads only after a while.
Does this means there is some configuration I'm missing to ensure it's rendered on server?
Material UI have a guide regarding server side rendering, but I don't think I'm supposed to use that since I'm relying on React.NET for this.
Are there any resources that would help with these?
The docs are here around SSR for styling. The Material UI guide is relevant, because it describes the necessary steps to accomplish it for that library (albeit in node). Taking the styled-components integration as an example, it essentially does the same thing, but using C# to call the JS:
using System;
namespace React.RenderFunctions
{
public class StyledComponentsFunctions : RenderFunctionsBase
{
public string RenderedStyles { get; private set; }
public override void PreRender(Func<string, string> executeJs)
{
executeJs("var serverStyleSheet = new Styled.ServerStyleSheet();");
}
public override string WrapComponent(string componentToRender)
{
return ($"serverStyleSheet.collectStyles({componentToRender})");
}
public override void PostRender(Func<string, string> executeJs)
{
RenderedStyles = executeJs("serverStyleSheet.getStyleTags()");
}
}
}
It works, as long as:
- In the view(s), you call
new StyledComponentsFunctions()and pass them to therenderFunctions. You also need to add the styles to theViewBag, e.g.:
@{
var styledComponentsFunctions = new StyledComponentsFunctions();
var pageDataModel = Html.GetReactPageDataModel<HomePage, HomePageDataModel>(Model);
}
<!-- Render React app, passing page data -->
@Html.React("Components.App", (object)pageDataModel, renderFunctions: styledComponentsFunctions )
@{
ViewBag.ServerStyles = styledComponentsFunctions.RenderedStyles;
}
- In the JS, you expose the
Styledfunction:
global.Styled = { ServerStyleSheet };
- In your template(s), you reference the server-generated styles:
<!doctype html>
<head>
@Html.Raw(ViewBag.ServerStyles)
...
ReactJS.NET calls the necessary functions (new Styled.ServerStyleSheet() etc. gathering your styles so we can output <style> tags). It's a little fragile, but that's really down to the nature of how the setup works.
To answer your question: using Material UI's SSR is not going to be particularly simple, because you will need to amend this library with the equivalent to the styled-components example.
One pointer: in Chrome/blink browsers you can easily disable JS in the dev tools. This lets you better test what is actually rendered server-side, and what depends on rehydration. Good luck!
I think this should be how it works, but again, not too sure.
import { ServerStyleSheets } from '@material-ui/styles'
global['MaterialUi'] = { ServerStyleSheets }Add this to component
React.useEffect(() => {
if (typeof window !== 'undefined') {
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentElement?.removeChild(jssStyles);
}
}
}, []); public class MaterialUIStyleFunctions : RenderFunctionsBase
{
/// <summary>
/// HTML style tag containing the rendered styles
/// </summary>
public string RenderedStyles { get; private set; }
public string Component { get; private set; }
/// <summary>
/// Implementation of PreRender
/// </summary>
/// <param name="executeJs"></param>
public override void PreRender(Func<string, string> executeJs)
{
executeJs("const sheets = new MaterialUi.ServerStyleSheets()");
}
/// <summary>
/// Implementation of WrapComponent
/// </summary>
/// <param name="componentToRender"></param>
/// <returns></returns>
public override string WrapComponent(string componentToRender)
{
Component = componentToRender;
return Component;
}
/// <summary>
/// Implementation of PostRender
/// </summary>
/// <param name="executeJs"></param>
public override void PostRender(Func<string, string> executeJs)
{
executeJs($"var comp = {Component}");
executeJs($"const html = ReactDOMServer.renderToString(sheets.collect(comp,))");
RenderedStyles = $"<style type=\"text/css\" id=\"jss-server-side\">{executeJs("sheets.toString()")}</style>";
}
}@KennyLMQ I'm trying to achieve a react.net and mui/emotion combo
Do you have any pointer on how too implement it?
Did you get the above suggestion to work?
@McDoit I gave up figuring how to do it. Sorry...
React.NET doesn't seems to be actively updated too, so I don't think I'll use it too.