Skip to content

Please do not pollute my DOM #45

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

Closed
MasodSaidi opened this issue Nov 15, 2014 · 8 comments
Closed

Please do not pollute my DOM #45

MasodSaidi opened this issue Nov 15, 2014 · 8 comments

Comments

@MasodSaidi
Copy link

Really like the server-side rendering but got one problem with it. Is it possible to not include the extra "react1" container div since it messes with the CSS. Would be great if there was an additional optional parameter on the helper like this:

@Html.React("HelloWorld", new {name = "Daniel"}, "my-own-container")

If the optional parameter is specified no "react1" div is rendered and the optional is used when doing:

document.getElementById("my-own-container")

@Daniel15
Copy link
Member

Thanks for reporting this! I had a TODO comment in the code to allow specifying the HTML tag to use, so you could do something like @Html.React("Hello World", new { name = "Daniel" }, "span") to render it in a span rather than a div. Would that solve your use case? ReactJS.NET needs to render a wrapper element of some sort, as it needs to be able to grab the exact element the server-side HTML was rendered to when initialising the component client-side.

@MasodSaidi
Copy link
Author

Yeap, a span solves my use case. Maybe it could be used as default since it is less obtrusive than div.

Ideally we would really want the wrapper to not be there at all, since its not expected. I have done some research, correct me if I am wrong. React components already have a wrapper div since siblings are not allowed.

div class="comments-box" data-reactid=".t66cpxj1cn" data-react-checksum="1948633873">...</div

Would it be possible to use following when initializing?

document.querySelector('[data-reactid=".t66cpxj1cn"]');

@Daniel15
Copy link
Member

I added the ability to select the tag you want to use in 303ab72. This is included in 1.1.4-dev-20141116-0842 and newer builds which you can get from the development NuGet server if you want to try it out (see http://reactjs.net/getting-started/download.html#development-builds)

I can't make span the default since it's an inline element, and inline elements can not contain block level elements. In most cases, people will probably have block level elements such as divs and uls in their components.

You can't manually touch any of the DOM nodes with data-reactid attributes as these are 'internal' to React and modifying them will leave things in a bad state. You always need a wrapper around the root element that you can call React.render on.

I'm going to close this task since there's now a fix available. Thanks for reporting it!

@MasodSaidi
Copy link
Author

Thanks for the quick fix!

@jhemminger
Copy link

Hi Daniel - I have the same need as was originally listed which was to be able to define the value of the ID instead of it being auto populated as react#. Should I open a new ticket? Or would you like me to make the changes and submit them? Let me know, thanks!

@mocanSergiu666
Copy link

mocanSergiu666 commented Apr 12, 2017

  1. Why when I use "setInterval" function with server-side rendering, I get an error that "setInterval" is undefined?
  2. If I specify "window.setInterval", then it errors that "window" is undefined.

@Daniel15
Copy link
Member

@mocanSergiu666 - setInterval can not be used when doing server rendering. setInterval is part of the BOM (Browser Object Model) which is not available in server-side JavaScript.

@oivindhagen
Copy link

oivindhagen commented Jun 29, 2017

To render just the component (with an optional reactId), the following extension method should do the trick:

using System.Web.Mvc;
using System.Web;
using System;
using React;
using Newtonsoft.Json;

namespace YourProject.Extensions
{
    public static class HtmlHelperExtensions
    {
        public static IHtmlString ReactWithoutContainer(this HtmlHelper helper, string componentName, object props)
        {
            var serializedProps = JsonConvert.SerializeObject(props, ReactSiteConfiguration.Configuration.JsonSerializerSettings);
            
            /*
            If you want to add a reactId to the top level element, uncomment the following three lines and render the 
            reactId property as an id attribute on the top level element in your component like this:
            <div id={reactId}>
            <!-- component content -->
            <div/>
            */
            //dynamic deserialized = JsonConvert.DeserializeObject(serializedProps, ReactSiteConfiguration.Configuration.JsonSerializerSettings);
            //deserialized.reactId = "react_" + Guid.NewGuid().ToShortGuid();
            //serializedProps = JsonConvert.SerializeObject(deserialized, ReactSiteConfiguration.Configuration.JsonSerializerSettings);

            var initializedCode = string.Format("React.createElement({0}, {1})", componentName, serializedProps);
            var code = string.Format("ReactDOMServer.renderToStaticMarkup({0})", initializedCode);
            return helper.Raw(React.ReactEnvironment.Current.Execute<string>(code));
        }
    }
}

To use it in your cshtml, just write the following:

    @Html.ReactWithoutContainer("Components.YourComponent", new
        {
            property1 = "value1",
            property2 = "value2"
        })

Please note that this extension method reaches quite far into ReactJs.net. It might get you into trouble down the road.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants