The unique ID that is generated on textfields seems to break server rendering. The generated html looks like this:
<input
name="query"
id="query-MerchantEmailAddress-undefined-19669"
style="-webkit-tap-highlight-color:rgba(0,0,0,0);padding:0;position:relative;width:100%;height:100%;border:none;outline:none;background-color:rgba(0,0,0,0);color:rgba(255, 255, 255, 1);font:inherit;mui-prepared:;"
type="text"
data-reactid=".s5vj4rstmo.0.$=10=2$=011.$=10.1.0.$=10.2"
>
I am getting the standard react checksum error:
warning.js:45 Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) ilAddress-undefined-19669" style="-webki
(server) ilAddress-undefined-46463" style="-webki
Well, that's annoying! Thanks for identifying it :+1:
Have the same problem. Setting the id manually gets around it.
I have the same problem and I'm on 0.15.0-beta.2
I'm seeing something similar on the client side. Here's how we are invoking TextArea:
<TextField
hintText={hintText}
multiLine={isMultiLine}
value={text}
errorText={errorText}
rows={rows}
onChange={e => this.setState({text: e.target.value})}
onBlur={(e) => this.handleBlur()}
onKeyDown={this.handleKeyDown}
floatingLabelText={floatingLabelText}
fullWidth={true}
underlineShow={false}
inputStyle={inputStyle}
style={style}
maxLength={maxLength}
/>
....and if I look at the generated source, I see IDs like this for the underlying DOM object:
undefined-Enteratitleforthiscard-undefined-21970
(The "hintText" in this case resolves to "Enter a title for this card...")
I'm also on 0.15.0-beta.2, on React 15.0.2 (npm/babel/webpack, if that's relevant)
Hope that's useful!
This line is using Math.random() to create a uniqueId in componentWillMount, which will produce conflicts in client and server sides.
@AJIh I could change it to a deterministic hash.
deterministic hash of what unique deterministic entity? Not as simple as it might sound :sweat_smile:
@alitaheri errrrrrr... 馃槄 馃槄
Ok, how about this: "provide an ID for server side rendering compatibility" -- lol (everyone knows that's how labels work)
You mean add that note to https://github.com/callemall/material-ui/blob/master/src/TextField/TextField.js#L290? sounds good :grin:
How about, we don't add label and htmlFor unless an id is provided. and document it in the TextField docs: "if you wanna support ARIA, add unique, deterministic ids to your text fields".
@alitaheri is that all we are doing it for? Users are accustomed to passing it for labels anyways.
yeah, take a look at the code, it's only one id and one htmlFor. do you think that's a good course of action? it might be slightly breaking, but very very slightly :grin: of course, for the sake of fixing SSR out of box
@alitaheri
+1. It's hard to find a unique deterministic entity to calculate hash. Setting id property manually is enough. But we should make sure that components based on TextField(like AutoComplete, DatePicker...) will pass id property to its children.
Since material-ui is using MuiThemeProvider to provide context to mui components. How about adding a function property to root provider context as uniqueID generator?
function getUniqueIdGenerator() {
let index = 0;
return () => {
return `mui-id-${index++}`;
};
}
class MuiThemeProvider extends Component {
static propTypes = {
children: PropTypes.element,
muiTheme: PropTypes.object.isRequired,
uniqueIdGen: PropTypes.func,
};
static childContextTypes = {
muiTheme: PropTypes.object.isRequired,
uniqueIdGen: PropTypes.func,
};
getChildContext() {
return {
muiTheme: this.props.muiTheme || getMuiTheme(),
uniqueIdGen: this.props.uniqueIdGen || getUniqueIdGenerator(),
};
}
render() {
return this.props.children;
}
}
I could change it to a deterministic hash.
Looks like I haven't implemented correctly this in https://github.com/callemall/material-ui/pull/3538. A PR is coming.
I'm also having this with a DatePicker:
id="undefined-PortraitDialog-undefined-8741"
Specifying an id on a <DatePicker/> seems to have worked around this issue.
Adding to @halt-hammerzeit's comment, adding an id prop to TextField solved the issue for me.
@nathanmarks have made the link between the label and the input more explicit on the next branch. E.g.
<TextField>
<TextFieldLabel htmlFor="name">
Name
</TextFieldLabel>
<TextFieldInput
id="name"
value={this.state.value}
onChange={(event) => this.setState({ value: event.target.value })}
/>
</TextField>
Making the link more explicit allow us to remove the magic _uniqueId_ generation.
And solve the server-side rendering issue.
I'm closing this issue as well as https://github.com/callemall/material-ui/pull/4253.
Most helpful comment
@nathanmarks have made the link between the label and the input more explicit on the
nextbranch. E.g.Making the link more explicit allow us to remove the magic _uniqueId_ generation.
And solve the server-side rendering issue.
I'm closing this issue as well as https://github.com/callemall/material-ui/pull/4253.