如何处理同构渲染表单的早期输入
How to handle early input to isomorphically rendered forms
我有一个包含表单的 React 应用程序,该表单在服务器端呈现,并预先填充了用户正在进行的工作。问题在于,如果用户在应用程序加载之前编辑了表单中的值,那么应用程序将不知道该更改。当用户保存时,服务器呈现的未更改数据被重新保存,用户的新数据被删除,尽管它仍然显示在表单中。简而言之,React 和最初加载时替换的标记中的输入值之间似乎存在脱节。
我想我可以在每个输入上放置 refs 并将它们的值复制到 componentDidMount 上的应用程序状态,但必须有更好的方法。有没有其他人解决了这个问题?
更新
我现在认为解决这个问题的最好方法是让 React 在创建校验和时考虑输入值。 GH 问题:https://github.com/facebook/react/issues/4293
如果我没理解错的话,情况是这样的:https://jsfiddle.net/9bnpL8db/1/
var Form = React.createClass({
render: function () {
return <div>
<input type="text" defaultValue={this.props.defaultValue}/>
</div>;
}
});
// Initial form render without server-side data
React.render(<Form/>, $('#container')[0]);
setTimeout(function () {
// Simulate server-side render
$('#container').html(
// overwrites input
React.renderToString(<Form defaultValue="server1"/>)
);
}, 5000);
不应使用服务器端渲染来进行更新。相反,应该使用服务器端呈现来创建初始页面,在用户有机会进行更改之前填充输入。要解决您的问题,我认为您有两种选择:
- 使用服务器端呈现来呈现初始页面,用保存的数据预填充输入。使用此选项,用户永远不会看到没有保存数据的页面。这消除了用户开始输入然后输入被服务器覆盖的问题。
- 使用客户端呈现来呈现页面并使用 GET 请求获取预填充的数据,如果用户尚未输入某些内容则更新输入。
I suppose I could put refs on every input and copy their values into the application state on componentDidMount, but there has got to be a better way. Has anyone else solved this problem?
浏览器自动填充字段或在刷新时记住以前的值也可能导致实际上相同的问题 - 您的应用对数据的看法与用户的不同。
我过去的暴力解决方案是从其输入中提取完整的表单状态 onSubmit
并在允许提交继续之前重新运行 验证。
按照您的建议使用 componentDidMount
听起来像是一个更优雅的解决方案,因为它避免了用户输入无效数据并被允许在收到任何警告之前尝试提交。不过,您不需要在每个输入中都添加 ref
;只需将一个添加到 <form>
并使用其 .elements
collection 提取所有数据。
建议的解决方案:
- 在
componentDidMount()
中,从其 .elements
中提取表单数据(为此,我从我的表单库中提取了 get-form-data)
- 根据您应用的状态检查每个字段的当前值。
- 如果一个字段的当前值不同,就像对待通过事件到达的新用户输入一样对待它 - 更新它的状态并重新运行任何关联的验证例程。
然后从 componentDidMount()
开始,您的应用程序和用户将始终在同一页面上(字面上)。
我有一个包含表单的 React 应用程序,该表单在服务器端呈现,并预先填充了用户正在进行的工作。问题在于,如果用户在应用程序加载之前编辑了表单中的值,那么应用程序将不知道该更改。当用户保存时,服务器呈现的未更改数据被重新保存,用户的新数据被删除,尽管它仍然显示在表单中。简而言之,React 和最初加载时替换的标记中的输入值之间似乎存在脱节。
我想我可以在每个输入上放置 refs 并将它们的值复制到 componentDidMount 上的应用程序状态,但必须有更好的方法。有没有其他人解决了这个问题?
更新
我现在认为解决这个问题的最好方法是让 React 在创建校验和时考虑输入值。 GH 问题:https://github.com/facebook/react/issues/4293
如果我没理解错的话,情况是这样的:https://jsfiddle.net/9bnpL8db/1/
var Form = React.createClass({
render: function () {
return <div>
<input type="text" defaultValue={this.props.defaultValue}/>
</div>;
}
});
// Initial form render without server-side data
React.render(<Form/>, $('#container')[0]);
setTimeout(function () {
// Simulate server-side render
$('#container').html(
// overwrites input
React.renderToString(<Form defaultValue="server1"/>)
);
}, 5000);
不应使用服务器端渲染来进行更新。相反,应该使用服务器端呈现来创建初始页面,在用户有机会进行更改之前填充输入。要解决您的问题,我认为您有两种选择:
- 使用服务器端呈现来呈现初始页面,用保存的数据预填充输入。使用此选项,用户永远不会看到没有保存数据的页面。这消除了用户开始输入然后输入被服务器覆盖的问题。
- 使用客户端呈现来呈现页面并使用 GET 请求获取预填充的数据,如果用户尚未输入某些内容则更新输入。
I suppose I could put refs on every input and copy their values into the application state on componentDidMount, but there has got to be a better way. Has anyone else solved this problem?
浏览器自动填充字段或在刷新时记住以前的值也可能导致实际上相同的问题 - 您的应用对数据的看法与用户的不同。
我过去的暴力解决方案是从其输入中提取完整的表单状态 onSubmit
并在允许提交继续之前重新运行 验证。
按照您的建议使用 componentDidMount
听起来像是一个更优雅的解决方案,因为它避免了用户输入无效数据并被允许在收到任何警告之前尝试提交。不过,您不需要在每个输入中都添加 ref
;只需将一个添加到 <form>
并使用其 .elements
collection 提取所有数据。
建议的解决方案:
- 在
componentDidMount()
中,从其.elements
中提取表单数据(为此,我从我的表单库中提取了 get-form-data) - 根据您应用的状态检查每个字段的当前值。
- 如果一个字段的当前值不同,就像对待通过事件到达的新用户输入一样对待它 - 更新它的状态并重新运行任何关联的验证例程。
然后从 componentDidMount()
开始,您的应用程序和用户将始终在同一页面上(字面上)。