question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Generating random/unique attributes server-side that don't break client-side mounting

See original GitHub issue

Consider, for example, a relatively generic <Field /> component:

var fieldCounter = 0;

var Field = React.createClass({
    getInitialState: function() {
        return { inputId: 'field-' + ++fieldCounter };
    },
    render: function() {
        var props = this.props,
            inputId = this.state.inputId;

        return (
            <div className='field'>
                <label htmlFor={inputId}>{props.label}</label>
                <input type={props.type} id={inputId} name={props.name} value='' />
            </div>
        );
    }
});

In order for the <label /> tag to be semantically related to the <input /> tag, we obviously need to match the for attribute to the <input /> tag’s id attribute. Outside of that requirement, however, we have no need of the id attribute, so a solution like the one above is convenient as it handles that all internally, with no need for a consuming component to pass in an actual id value.

The problem I’m running into, however, is that this causes the id attributes generated client-side to mismatch what was sent down by the server (the client-side fieldCounter restarts at 0 on every load, whereas the server-side reference obviously just keeps growing).

This mismatch then results in an error being thrown:

Invariant Violation: You're trying to render a component to the document using server rendering [...]

So, my question is this: am I overlooking an obvious solution here? I would like for the <Field /> component to be able to simply internalize the id generation as an implementation detail, but I can’t seem to come up with a good mechanism for then matching up that id generation client-side.

Thanks in advance!

Issue Analytics

  • State:closed
  • Created 8 years ago
  • Reactions:1
  • Comments:17 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
syranidecommented, Jun 7, 2015

There have actually been some talks internally about requiring all IO go through React. And that things like getTime (and therefore, transitively, getRandomNumber) would count as IO. I think the idea was proposed mostly for academic purposes (a thought exercise, not a proposal for implementation), but this might add fuel to that discussion.

Those are interesting discussions, but I’m curious exactly what you mean by “requiring all IO go through React”, what kinds of IO is it referring to? (Or is it in the sense that no data should exist outside of components, like Flux stores does? So all data can be serialized and is guaranteed to represent the entire state?)

My replies below are purely gut feeling, intuition and brainstorming 😃

Suppose we provide a UUID generator, and we provide a time api, and we provide… [we can create a huge list of possible APIs to provide, but how do we know we’ve covered everyone else’s use cases?]. My preference is to provide basic building blocks, from which people can build whatever they want/need. So the question is: what is the common theme / underlying API that would make it easier to implement these things in user land? Where does context/sideways-data fall short of what is needed?

The way I see it, if you give me (per-root) Time, a Seed, a UUID and a way to store per-root local data. With that a component should be able to accomplish any useful deterministic process without requiring any additional data be sent from client to server.

UUID is only necessary for producing markup with GUIDs, which seems like a necessity only because of HTML deficiencies and should not otherwise be useful I think… but it might have other uses.

I think the key point of these features is there is no benefit in having more that one definition/source of each, it’s probably only detrimental even. But these are values that have to be transferred from server to client, if React does not provide these then components has to make these demands on other libraries or on the consumer of the component, neither of which seems at all beneficial (because it’s redundant, leads to duplication of data and code, inconsistencies, etc).

But Time, Seed and UUID have fairly limited usefulness to reusable components and when those are needed they could be provided on an as-needed basis by the consumer if we want to be hands-off (but UUID is intrinsically useful to some reusable ReactDOM components). So I think the primary issue is that per-root local data simply doesn’t exist currently, because even if you have Seed you’re unable to use it for anything stateful because you have nowhere appropriate to store the data without putting explicit requirements on the consumer for making specific per-root data storage available through context (which is a slippery slope from a maintenance perspective).

What if we (somehow, magically) allowed a context variable to have a default value.

So yeah it seems to me that (technically) it is indeed a solution to the above lack of “root local data”, which is the primary problem. 👍

What to do about Time, Seed and UUID is a secondary problem. We may decide not to provide some/all in core, but I think it would be a mistake not to at least make them available as separate “preferred” modules (possibly even just as interfaces). So that reusable components can specify them as dependencies. But again, less of an immediate concern.

PS. I think clock must be a function, it has to be on-demand.

1reaction
jimfbcommented, Jun 5, 2015

Mostly brainstorming here, so I’d be curious to hear what the rest of the team thinks (and nothing I say here constitutes an official recommendation). Personally, I would go with option number 2.

What you’re really looking for is a UUID, but you don’t want to use random because then the markup wouldn’t match 😕.

Ultimately, this is the server-side-clock problem (ie. suppose you had a component that rendered the current time displaying microsecond accuracy; the two machines are going to have clock skew, making it impossible to generate matching markup). Incidentally, since rand() reads the clock, it’s literally the same problem 😛.

When framing the problem as the server-side-clock problem, I think it’s pretty clear that you want to have some way of controlling the current time (perhaps you want the clock to be red&green on christmas, and have eggs&bunnies on easter) because you need a way to test this functionality more than once per year. To write unit tests to verify the functionality, you would need to control the time.

The difference is that, for your component, your need for a unique identifier is an implementation detail not visible to the user, so the dependency on sideways data kinda sucks. Eeh, not sure what to do about that.

In the near future, you will be able to get around the cumbersome passing-down-props problem by using context (actually, you could use it today, but it’s officially undocumented and unsupported and subject to change).

In the more distant future, you will be able to use sideways data loading, perhaps in combination with context, to subscribe to external data like the clock.

@jmar777 does that help a little? @sebmarkbage thoughts?

Read more comments on GitHub >

github_iconTop Results From Across the Web

Server Side Rendering a Random Number
If the problem is that the server and client are generating different numbers, then we need a way for them to generate the...
Read more >
Next.js, using random properties without triggering "did not ...
Any idea how to generate a random id that's consistent on the server/client? Or maybe a different way of doing it without random...
Read more >
Server-side rendered styled-components with Nextjs
To enable server side rendering of the styles, we will need to do two ... of a page // Step 1: Here we...
Read more >
The future of rendering in React
Understand what are the problems with current rendering patterns in React, and how the new rendering patterns introduced with React 18 and ...
Read more >
Components: Server-Side vs. Client-Side
These frameworks have mechanisms for creating a superior in-app experience. What I mean is that, while they may be slower to load the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found