在 React.js 表单组件中使用 state 或 ref?

我从 React.js 开始,想做一个简单的表单,但是在文档中我找到了两种方法。

第一个使用的是 裁判:

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>
);
}
});

第二个在 React 组件内部使用 国家:

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: ''
});
});

我看不出这两种选择的利弊,如果存在的话。 谢谢。

83842 次浏览

简而言之: 避免引用。


它们不利于可维护性,并且失去了所见即所得模型渲染提供的许多简单性。

您有一个窗体。您需要添加一个按钮来重置该窗体。

  • 参考文献:
    • 操纵 DOM
    • 渲染描述了表单3分钟前的样子
  • 国家
    • SetState
    • 渲染描述了表单的外观

在输入中有一个 CCV 数字字段,在应用程序中有一些其他的数字字段。现在您需要强制用户只输入数字。

  • 参考文献:
    • 添加一个 onChange 处理程序(难道我们不使用参考文献来避免这种情况吗?)
    • 如果它不是一个数字,改变它
  • 国家
    • 您已经有了一个 onChange 处理程序
    • 添加一个 if 语句,如果它是无效的,什么都不做
    • 只有当它要产生一个不同的结果时才会被调用

呃,没关系,首相要我们做一个红盒子的影子,如果它是无效的。

  • 参考文献:
    • 调用 forcUpdate 或者别的什么?
    • 基于... 制作渲染输出?
    • 我们在哪里得到的值验证在渲染?
    • 手动操作元素的 className dom 属性?
    • 我迷路了
    • 重写没有参考?
    • 在渲染中读取 Dom,如果我们被安装,否则假设有效?
  • 国家:
    • 删除 if 语句
    • 基于 this. state 进行渲染验证

我们得把控制权还给父母。数据现在在道具中,我们需要对变化做出反应。

  • 参考文献:
    • 实现组件 DidMount、组件 WillUpdate 和组件 DidUpdate
    • 手动区分以前的道具
    • 用最小的变更集操纵领地
    • 嘿! 我们正在实施反应..。
    • 还有,但我手指疼
  • 国家:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

人们认为裁判比保持状态更“容易”。在开始的20分钟里可能是这样,但之后的经历就不是这样了。把你自己放在一个说“是的,我会在5分钟内完成”的位置,而不是“当然,我只是重写一些组件”。

我看到一些人引用上述答案作为“永远不要使用参考文献”的理由,我想给出我的(以及其他一些与我交谈过的 React 开发人员)观点。

在讨论将它们用于组件实例时,“不使用 ref”的观点是正确的。也就是说,不应该使用引用作为获取组件实例并调用它们的方法的方法。这是使用参考文献的不正确的方法,而且是当参考文献迅速南下的时候。

使用引用的正确(而且非常有用)方法是使用它们从 DOM 获取一些值。例如,如果有一个输入字段将 ref 附加到该输入,那么稍后通过 ref 获取该值就可以了。如果没有这种方式,您需要经过一个相当精心安排的过程来保持您的输入字段与您的本地状态或您的通量存储保持最新-这似乎是不必要的。

2019编辑: 你好,未来的朋友们。除了我几年前提到的 ^ ,通过 React Hooks,引用也是跟踪呈现之间的数据的一个很好的方法,而且不仅仅局限于抓取 DOM 节点。

一般来说,refs与 React 的 陈述哲学相反,所以你应该把它们作为最后的手段。尽可能使用 state / props


为了理解在哪里使用 refsstate / props,让我们看看 React 遵循的一些设计原则。

每反应 文件refs

避免对任何可以声明方式执行的操作使用引用。

逃生舱的按反应器设计原则

如果一些对于构建应用程序有用的模式很难以声明的方式表示,我们将为其提供一个命令式 API。(他们链接到这里的参考文献)

这意味着 React 的团队建议避免使用 refs,并且在任何可以通过反应/声明方式完成的事情上使用 state / props

@ Tyler McGinnis 提供了非常好的 回答

使用引用的正确(而且非常有用)方法是当您使用它们从 DOM 获取一些值时..。

虽然你可以做到这一点,你将工作反应的哲学。如果输入中有值,那么它肯定来自 state / props。为了保持代码的一致性和可预测性,还应该坚持使用 state / props。我承认,refs有时给你更快的解决方案,所以如果你做一个概念证明,又快又脏是可以接受的。

这使我们有几个 具体用例refs

管理焦点、文本选择或媒体回放。 触发命令式动画。 与第三方 DOM 库集成。

这个帖子很旧了。

我会分享一个案子的经验。

我当时正在处理一个大型组件(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)}

渲染是如此的繁重,以至于输入变化像 * * * * 一样不稳定(不要试图保持关键,文本只会在暂停后出现)

我确信使用参考文献可以避免这种情况。

结果是这样的:

  const inputsRef = useRef([])

以及输入:

ref={input => (inputsRef.current[id] = input)}

[ 在我的例子中,输入是材料-UI 文本字段,所以它是:

inputRef={input => (inputsRef.current[id] = input)}

]

由于这一点,没有重新渲染,输入是平滑的, 函数性也是这样工作的。它将节省周期和计算,所以能源也。为了地球 x)

我的结论是: 对于输入值的 useRef 甚至是必需的。