在 React.js 表单组件中使用 state 或 refs?
Use state or refs in React.js form components?
我从 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: ''
});
});
我看不出这两种选择的优缺点(如果存在的话)。
谢谢。
简短版本:避免引用。
它们不利于可维护性,并且失去了所见即所得模型渲染提供的很多简单性。
你有一个表格。您需要添加一个重置表单的按钮。
- 参考:
- 操纵DOM
- 渲染描述表单在 3 分钟前的样子
- 状态
- 设置状态
- 渲染描述表单的外观
您在输入中有一个 CCV 数字字段,在您的应用程序中有一些其他字段是数字。现在您需要强制用户只输入数字。
- 参考:
- 添加一个 onChange 处理程序(我们不是使用 refs 来避免这种情况吗?)
- 如果不是数字,则在 onChange 中处理 dom
- 状态
- 您已经有一个 onChange 处理程序
- 添加一个 if 语句,如果它无效则什么都不做
- render 只有在要产生不同的结果时才会被调用
呃,没关系,如果无效,PM 要我们只做一个红色框阴影。
- 参考:
- 让 onChange 处理程序只调用 forceUpdate 或其他东西?
- 根据...制作渲染输出?
- 我们从哪里获取要在渲染中验证的值?
- 手动操作元素的类名dom属性?
- 我迷路了
- 不使用引用重写?
- 如果我们已安装,则从渲染中的 dom 读取,否则假设有效?
- 状态:
- 删除 if 语句
- 根据this.state
进行渲染验证
我们需要将控制权交还给父级。数据现在在道具中,我们需要对变化做出反应。
- 参考:
- 实施 componentDidMount、componentWillUpdate 和 componentDidUpdate
- 手动比较之前的道具
- 使用最少的一组更改来操纵 dom
- 嘿!我们在反应中实施反应...
- 还有很多,但我的手指受伤了
- 状态:
sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js
人们认为 refs 'easier' 而不是保持状态。这在前 20 分钟内可能是正确的,但根据我之后的经验,情况并非如此。把你自己放在说 "Yeah, I'll have it done in 5 minutes" 而不是 "Sure, I'll just rewrite a few components".
的位置
我看到一些人引用上述答案作为 "never use refs" 的理由,我想发表我(以及我与之交谈过的其他一些 React 开发人员)的意见。
在谈论将它们用于组件实例时,"don't use refs" 观点是正确的。意思是,你不应该使用 refs 来获取组件实例并调用它们的方法。这是使用 refs 的不正确方法,并且是 refs 迅速向南移动的时候。
使用 ref 的正确(并且非常有用)的方法是当您使用它们从 DOM 中获取一些值时。例如,如果您有一个输入字段将 ref 附加到该输入,那么稍后通过 ref 获取值就可以了。如果没有这种方式,您需要通过一个相当精心安排的过程来使您的输入字段与您的本地状态或您的通量存储保持同步——这似乎是不必要的。
2019 编辑:你好未来的朋友们。除了我几年前提到的 ^,使用 React Hooks,refs 也是跟踪渲染之间数据的好方法,并且不仅限于抓取 DOM 个节点。
TL;DR 一般来说,refs
与 React 的 背道而驰,因此您应该将它们作为最后的手段使用。尽可能使用 state / props
。
要了解您在哪里使用 refs
与 state / props
,让我们看看 React 遵循的一些设计原则。
每个 React documentation 大约 refs
Avoid using refs for anything that can be done declaratively.
根据 React 的设计原则 Escape Hatches
If some pattern that is useful for building apps is hard to express in a declarative way, we will provide an imperative API for it. (and they link to refs here)
这意味着 React 的团队建议避免 refs
并使用 state / props
来处理任何可以以反应式/声明式方式完成的事情。
@Tyler McGinnis 提供了非常好的 ,并指出
The correct (and very useful) way to use refs is when you're using them to get some value from the DOM...
虽然你可以这样做,但你将违背 React 的理念。如果您在输入中有价值,它肯定来自 state / props
。为了保持代码的一致性和可预测性,您也应该坚持使用 state / props
。我承认 refs
有时会给您更快的解决方案,因此如果您进行概念验证,快速而肮脏的 是可以接受的。
这为 refs
留下了几个 concrete use cases
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
这个post是旧的。
我就一个案例分享一下我在这方面的一点经验。
我正在处理一个大型组件(414 行),其中包含大量 'dynamic' 输入和大量缓存数据。
(我不是一个人在页面上工作,我的感觉告诉我代码的结构可能会更好地拆分,但这不是重点(好吧,它可能是但我正在处理它)
我首先使用状态来处理输入值:
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 作为输入值。
我从 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: ''
});
});
我看不出这两种选择的优缺点(如果存在的话)。 谢谢。
简短版本:避免引用。
它们不利于可维护性,并且失去了所见即所得模型渲染提供的很多简单性。
你有一个表格。您需要添加一个重置表单的按钮。
- 参考:
- 操纵DOM
- 渲染描述表单在 3 分钟前的样子
- 状态
- 设置状态
- 渲染描述表单的外观
您在输入中有一个 CCV 数字字段,在您的应用程序中有一些其他字段是数字。现在您需要强制用户只输入数字。
- 参考:
- 添加一个 onChange 处理程序(我们不是使用 refs 来避免这种情况吗?)
- 如果不是数字,则在 onChange 中处理 dom
- 状态
- 您已经有一个 onChange 处理程序
- 添加一个 if 语句,如果它无效则什么都不做
- render 只有在要产生不同的结果时才会被调用
呃,没关系,如果无效,PM 要我们只做一个红色框阴影。
- 参考:
- 让 onChange 处理程序只调用 forceUpdate 或其他东西?
- 根据...制作渲染输出?
- 我们从哪里获取要在渲染中验证的值?
- 手动操作元素的类名dom属性?
- 我迷路了
- 不使用引用重写?
- 如果我们已安装,则从渲染中的 dom 读取,否则假设有效?
- 状态:
- 删除 if 语句
- 根据this.state 进行渲染验证
我们需要将控制权交还给父级。数据现在在道具中,我们需要对变化做出反应。
- 参考:
- 实施 componentDidMount、componentWillUpdate 和 componentDidUpdate
- 手动比较之前的道具
- 使用最少的一组更改来操纵 dom
- 嘿!我们在反应中实施反应...
- 还有很多,但我的手指受伤了
- 状态:
sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js
人们认为 refs 'easier' 而不是保持状态。这在前 20 分钟内可能是正确的,但根据我之后的经验,情况并非如此。把你自己放在说 "Yeah, I'll have it done in 5 minutes" 而不是 "Sure, I'll just rewrite a few components".
的位置我看到一些人引用上述答案作为 "never use refs" 的理由,我想发表我(以及我与之交谈过的其他一些 React 开发人员)的意见。
在谈论将它们用于组件实例时,"don't use refs" 观点是正确的。意思是,你不应该使用 refs 来获取组件实例并调用它们的方法。这是使用 refs 的不正确方法,并且是 refs 迅速向南移动的时候。
使用 ref 的正确(并且非常有用)的方法是当您使用它们从 DOM 中获取一些值时。例如,如果您有一个输入字段将 ref 附加到该输入,那么稍后通过 ref 获取值就可以了。如果没有这种方式,您需要通过一个相当精心安排的过程来使您的输入字段与您的本地状态或您的通量存储保持同步——这似乎是不必要的。
2019 编辑:你好未来的朋友们。除了我几年前提到的 ^,使用 React Hooks,refs 也是跟踪渲染之间数据的好方法,并且不仅限于抓取 DOM 个节点。
TL;DR 一般来说,refs
与 React 的 state / props
。
要了解您在哪里使用 refs
与 state / props
,让我们看看 React 遵循的一些设计原则。
每个 React documentation 大约 refs
Avoid using refs for anything that can be done declaratively.
根据 React 的设计原则 Escape Hatches
If some pattern that is useful for building apps is hard to express in a declarative way, we will provide an imperative API for it. (and they link to refs here)
这意味着 React 的团队建议避免 refs
并使用 state / props
来处理任何可以以反应式/声明式方式完成的事情。
@Tyler McGinnis 提供了非常好的
The correct (and very useful) way to use refs is when you're using them to get some value from the DOM...
虽然你可以这样做,但你将违背 React 的理念。如果您在输入中有价值,它肯定来自 state / props
。为了保持代码的一致性和可预测性,您也应该坚持使用 state / props
。我承认 refs
有时会给您更快的解决方案,因此如果您进行概念验证,快速而肮脏的 是可以接受的。
这为 refs
Managing focus, text selection, or media playback. Triggering imperative animations. Integrating with third-party DOM libraries.
这个post是旧的。
我就一个案例分享一下我在这方面的一点经验。
我正在处理一个大型组件(414 行),其中包含大量 'dynamic' 输入和大量缓存数据。 (我不是一个人在页面上工作,我的感觉告诉我代码的结构可能会更好地拆分,但这不是重点(好吧,它可能是但我正在处理它)
我首先使用状态来处理输入值:
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 作为输入值。