在 React.js 表单组件中使用 state 或 refs?
Posted
技术标签:
【中文标题】在 React.js 表单组件中使用 state 或 refs?【英文标题】:Use state or refs in React.js form components? 【发布时间】:2015-06-12 17:39:54 【问题描述】:我从 React.js 开始,我想做一个简单的表单,但在文档中我发现了两种方法。
first one 正在使用 Refs:
var CommentForm = React.createClass(
handleSubmit: function(e)
e.preventDefault();
var author = React.findDOMNode(this.refs.author).value.trim();
var text = React.findDOMNode(this.refs.text).value.trim();
if (!text || !author)
return;
// TODO: send request to the server
React.findDOMNode(this.refs.author).value = '';
React.findDOMNode(this.refs.text).value = '';
return;
,
render: function()
return (
<form className="commentForm" onSubmit=this.handleSubmit>
<input type="text" placeholder="Your name" ref="author" />
<input type="text" placeholder="Say something..." ref="text" />
<input type="submit" value="Post" />
</form>
);
);
second one 在 React 组件中使用 state:
var TodoTextInput = React.createClass(
getInitialState: function()
return
value: this.props.value || ''
;
,
render: function() /*object*/
return (
<input className=this.props.className
id=this.props.id
placeholder=this.props.placeholder
onBlur=this._save
value=this.state.value
/>
);
,
_save: function()
this.props.onSave(this.state.value);
this.setState(value: ''
);
);
如果存在的话,我看不出这两种选择的优缺点。 谢谢。
【问题讨论】:
我在这里遗漏了什么吗?为什么不使用事件对象来获取表单值?这似乎是首先在这里使用表格的唯一原因。如果您没有使用默认提交行为并且在输入上有引用,则不需要将它们包装在表单中。 【参考方案1】:这篇文章很旧。
我将在这件事上分享我对一个案例的小经验。
我正在研究一个包含大量“动态”输入和大量缓存数据的大型组件(414 行)。 (我不是一个人在页面上工作,我的感觉告诉我,代码的结构可能可以更好地拆分,但这不是重点(嗯,可能是,但我正在处理它)
我首先使用 state 来处理输入的值:
const [inputsValues, setInputsValues] = useState([])
const setInputValue = (id, value) =>
const arr = [...inputsValues]
arr[id] = value
setInputsValues(arr)
当然还有输入:
value=inputsValues[id] || ''
onChange=event => setInputValue(id, event.target.value)
渲染非常繁重,以至于输入变化断断续续,就像****一样(不要试图按住键,文本只会在暂停后出现)
我确信我可以使用 refs 避免这种情况。
结果是这样的:
const inputsRef = useRef([])
在输入中:
ref=input => (inputsRef.current[id] = input)
[ 在我的情况下,输入是 Material-UI TextField 所以它是:
inputRef=input => (inputsRef.current[id] = input)
]
多亏了这一点,没有重新渲染,输入流畅,功能以同样的方式工作。它将节省周期和计算,也可以节省能源。为地球做这件事x)
我的结论:甚至可能需要用于输入值的 useRef。
【讨论】:
【参考方案2】:我看到一些人引用上述答案作为“从不使用 refs”的理由,我想给出我(以及我与之交谈过的其他一些 React 开发人员)的意见。
在谈论将它们用于组件实例时,“不要使用 refs”的观点是正确的。这意味着,您不应该使用 refs 作为获取组件实例并在其上调用方法的一种方式。这是使用 refs 的不正确方式,并且当 refs 快速向南时。
使用 refs 的正确(并且非常有用)的方法是当您使用它们从 DOM 中获取一些值时。例如,如果您有一个输入字段将 ref 附加到该输入,那么稍后通过 ref 获取值就可以了。如果没有这种方式,您需要经过一个相当协调的过程,以使您的输入字段与您当地的州或助焊剂商店保持同步——这似乎没有必要。
2019 年编辑:未来的朋友你好。除了我几年前提到的 ^ 之外,使用 React Hooks,refs 也是在渲染之间跟踪数据的好方法,并且不仅限于抓取 DOM 节点。
【讨论】:
你的最后一段很有道理,但你能澄清一下你的第二段吗?获取组件实例并调用被认为不正确的方法的具体示例是什么? 我同意这一点。我使用 refs 除非/直到我需要对字段的值进行验证或操作。如果我确实需要验证更改或以编程方式更改值,那么我使用状态。 我也同意这一点。在发现阶段,我故意天真地接近了一个包含大量输入的屏幕。存储在由 id 键入的映射(处于状态)中的所有输入值。不用说,由于设置状态和渲染 50 多个输入(一些 material-ui,它们很重!)在这样的微小 UI 更改上(如复选框单击并不理想),因此性能受到了影响。将每个可以保持其自身状态的输入组件化似乎是正确的方法。如果需要对账,只需查看refs
并获取状态值。实际上,这似乎是一个非常好的模式。
我完全同意。在我看来,接受的答案太模糊了。
我同意。在设计通用表单组件时,这暴露了受控组件和管理焦点、错误处理等的痛点。实际上不可能有一个干净的架构。如果需要,请与我交谈。我正在将我的组件移动到 refs。【参考方案3】:
TL;DR 一般来说,refs
与 React 的 declarative philosophy 相悖,所以你应该将它们作为最后的手段。尽可能使用state / props
。
要了解refs
和state / props
在哪里使用,让我们看一下 React 遵循的一些设计原则。
每个反应 documentation 关于 refs
避免将 refs 用于任何可以以声明方式完成的事情。
Per React 关于Escape Hatches的设计原则
如果某些对构建应用程序有用的模式难以以声明性方式表达,我们将为它提供命令式 API。 (他们在这里链接到参考)
这意味着 React 的团队建议避免使用 refs
并使用 state / props
来处理可以以反应/声明方式完成的任何事情。
@Tyler McGinnis 提供了一个非常好的answer,并指出
使用 refs 的正确(并且非常有用)的方式是当您使用它们从 DOM 中获取一些值时......
虽然您可以这样做,但您将违背 React 的理念。如果你的输入有价值,它肯定来自state / props
。为了保持代码的一致性和可预测性,您也应该坚持使用state / props
。我承认refs
有时会为您提供更快的解决方案这一事实,因此如果您进行概念验证,又快又脏 是可以接受的。
这给我们留下了几个concrete use cases 用于refs
管理焦点、文本选择或媒体播放。 触发命令式动画。 与第三方 DOM 库集成。
【讨论】:
【参考方案4】:简短版本:避免引用。
它们不利于可维护性,并且失去了所见即所得模型渲染提供的许多简单性。
你有一个表格。您需要添加一个重置表单的按钮。
参考: 操作 DOM render 描述了表单在 3 分钟前的样子 状态 设置状态 render 描述了表单的外观您的输入中有一个 CCV 编号字段,而您的应用程序中有一些其他字段是数字。现在你需要强制用户只输入数字。
参考: 添加一个 onChange 处理程序(我们不是使用 refs 来避免这种情况吗?) 如果不是数字,则在 onChange 中操作 dom 状态 您已经有一个 onChange 处理程序 添加 if 语句,如果无效则什么都不做 只有在要产生不同结果时才会调用渲染呃,没关系,如果它无效,PM 想要我们只做一个红色框阴影。
参考: 让 onChange 处理程序只调用 forceUpdate 什么的? 根据...制作渲染输出是吧? 我们从哪里获得要在渲染中验证的值? 手动操作元素的 className dom 属性? 我迷路了 没有引用重写? 如果我们已安装,则从渲染中的 dom 读取,否则假定有效? 状态: 删除 if 语句 根据 this.state 进行渲染验证我们需要将控制权交还给父级。数据现在在 props 中,我们需要对变化做出反应。
参考: 实现 componentDidMount、componentWillUpdate 和 componentDidUpdate 手动区分之前的props 用最少的更改来操作 dom 嘿!我们正在 react 中实现 react... 还有更多,但我的手指受伤了 状态:sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js
人们认为 refs 比保持状态“更容易”。前 20 分钟可能是这样,但在我之后的经验中,情况并非如此。让你自己说“是的,我会在 5 分钟内完成”,而不是“当然,我会重写一些组件”。
【讨论】:
你能解释一下 sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js 吗? 不,我的意思是对 dom 的实际更改。React.findDOMNode(this.refs.foo)
。如果你例如更改this.refs.foo.props.bar
不会发生任何事情。
例如如果您有 <input onChange=this.handleChange value=this.state.foo />
将其更改为 <input onChange=this.props.handleChange value=this.props.foo />
,或修改您的 handleChange 函数以调用 props 中的回调。无论哪种方式,这都是一些明显的小变化。
不确定我是不是唯一一个觉得你的答案有点混乱的人。您能否展示一些代码示例,让您的观点更清楚?
在屏幕上有 50 多个输入,并且在任何状态更改时都进行渲染是不可取的。组件化每个维护自己状态的input
字段是理想的。在某些时候,我们确实需要用一些更大的模型来协调这些不同的独立状态。也许我们在计时器上有一个自动保存,或者我们只是保存在componentWillUnmount
这是我发现refs
理想的地方,在协调过程中,我们从每个ref
中提取state
值,没有一个是更明智的。我同意在大多数情况下state
是答案,但是对于大量的inputs
,使用适当的refs
模式是一个性能提升以上是关于在 React.js 表单组件中使用 state 或 refs?的主要内容,如果未能解决你的问题,请参考以下文章