-
Notifications
You must be signed in to change notification settings - Fork 32
Question regarding patterns with autofill and server rendering #3
Comments
I read through the article but didn't fully understand what the problem was (though from the title I expect I understand it) or what caused it:
Why is this the case? Shouldn't they have initial state rehydrated from the server (provided by |
Scratch that last (deleted) comment, I cannot reproduce the issue. If you take a look at this branch: https://github.com/davezuko/react-reformed/tree/server-demo ( Server rendering code is here: https://github.com/davezuko/react-reformed/blob/server-demo/demo/server/app.js. The form looks right both loaded as a static page (i.e. no React app to resume on the client) and with the backing client app. So basically, where I'm at with this is: I don't really have a unique way of approaching this. The form is just rendered straight through props, without any ref usage (which I think is what If I'm missing something, please let me know. |
When i'm talking about autofill, i'm referring to browser behaviour to fill in fields that it recognises with values from it's database, i.e. when Chrome makes the field backgrounds turn yellow. With client-only rendering, this happens:
With server-side rendering:
This is specific example of the general issue with forms and server-side rendering, which is that if you're using a state object to hold form values, it's possible for them to get out of sync with the DOM, because changes can happen before React is initialized and able to handle them. The solution in the article reads the current values of the fields from the DOM when the form is mounted. It's the only solution i'm aware of for this type of problem, it's just unfortunately because it breaks the purity of never reading the DOM that we get with the client-only solution. |
Ok, I understand the problem now, sorry for being so dense. For clarity, what I was missing was that extra step in the sequence of events, since the auto-filling does work. You hint at it in one of the points, but I think it's crucial to point out explicitly:
I've seen this problem brought up before, in fact the first place I saw it tackled was in an Angular 2 talk (found it, here: https://www.youtube.com/watch?v=0wvZ7gakqV4#t=10m30s). Their approach (called The |
So I just did come up with an idea, but I think explicit const rehydrateFromDOM = (WrappedComponent) => {
class RehydratableFromDOM extends React.Component {
componentDidMount () {
const form = ReactDOM.findDOMNode(this._form)
// this currently only looks for inputs, and is pretty specific, so it would
// have to be expanded to fit your needs.
const model = [...form.querySelectorAll('input')]
.reduce((acc, input) => {
switch (input.type) {
case 'checkbox':
if (input.checked) {
acc[input.name] = (acc[input.name] || []).concat(input.value)
}
break
default:
acc[input.name] = input.value
}
return acc
}, {})
this.props.setModel(model)
}
_onRef = (el) => {
this._form = el
}
render () {
return React.createElement(WrappedComponent, {
...this.props,
ref: this._onRef,
})
}
}
return RehydratableFromDOM
} Then you can use it as follows: const createFormContainer = compose(
reformed(),
rehydrateFromDOM,
)
createFormContainer(YourForm) I delayed rendering, messed with the inputs, and then initialized the client application manually. It correctly rehydrated the model from what existed in the DOM, so it at least works on a prototype level. The one big gotcha with this, of course, is that none of the higher order components can be stateless since they cannot have |
I found this issue when I was looking into the same problem, and I found the preboot library. I've yet to implement it, but it seems like it may be a good way around these problems. It works by being the first thing to load on the page, and then listening for input events, which can then be played back after the client code has rendered/bootstrapped. |
As explained pretty well in this article, autofill creates a few problems with server-side rendering, because the change event happens before React finishes initialising. So we end up back on the world of having to use refs and reading the DOM when mounting the form. I'm wondering if you have any preferred patterns for this.
The text was updated successfully, but these errors were encountered: