这里有三个答案,这取决于你(被迫)使用的 React 版本,以及你是否想要使用钩子。
第一件事:
了解 React 的工作原理很重要,这样你才能正确地做事(提示:通过 React 网站上的 React 教程练习是非常值得的。它写得很好,并以一种实际解释如何做事的方式涵盖了所有基础知识)。这里的“正确”意味着您正在编写一个恰好在浏览器中呈现的应用程序界面;所有的界面工作都发生在 React 中,而不是“你在写网页时习惯的东西”(这就是为什么 React 应用程序是“应用程序”,而不是“网页”)。
React 应用程序的呈现基于两件事:
- 由任何父级声明的组件属性创建该组件的实例,父级可以在其整个生命周期中修改该实例,以及
- 组件自己的内部状态,它可以在整个生命周期中修改自己。
当您使用 React 时,您明确没有做的是生成 HTML 元素然后使用这些元素:<input>
例如,当您告诉 React 使用 an 时,您不是在创建 HTML 输入元素,而是在告诉 React 创建一个 React 输入对象恰好呈现为 HTML 输入元素,其事件处理查看HTML 元素的输入事件,但不受 控制。
使用 React 时,您所做的是生成应用程序 UI 元素,向用户呈现(通常是可操作的)数据,用户交互会改变组件的状态,这可能会导致应用程序界面的一部分重新呈现以反映新状态。在这个模型中,状态始终是最终的权威,而不是“使用任何 UI 库来渲染它”,在网络上它是浏览器的 DOM。在这个编程模型中,DOM 几乎是事后的想法:它只是 React 碰巧使用的特定 UI 框架。
所以在输入元素的情况下,逻辑是:
- 你输入输入元素,
- 您的输入元素还没有发生任何事情,该事件被 React 拦截并立即终止,
- React 将事件转发到您为事件处理设置的函数,
- 该函数可以安排状态更新,
- 如果是,React 运行该状态更新(异步!)并会
render
在更新后触发调用,但前提是状态更新更改了状态。
- 只有在此渲染发生后,UI 才会显示您“键入了一个字母”。
所有这一切都在几毫秒内发生,如果不是更短的话,所以看起来您以与“仅在页面上使用输入元素”相同的方式输入输入元素,但这绝对不是什么发生了。
所以,话虽如此,关于如何从 React 中的元素获取值:
React 15 及以下,使用 ES5
为了正确地做事,你的组件有一个状态值,它通过输入字段显示,我们可以通过让 UI 元素将更改事件发送回组件来更新它:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
所以我们告诉 React 使用该updateInputValue
函数来处理用户交互,使用它setState
来安排状态更新,事实上,render
tap intothis.state.inputValue
意味着当它在更新状态后重新渲染时,用户将根据他们输入的内容看到更新文本。
基于评论的附录
鉴于 UI 输入表示状态值(考虑如果用户在中途关闭他们的选项卡,并且选项卡被恢复会发生什么。他们填写的所有这些值是否应该被恢复?如果是,那就是状态)。这可能会让你觉得一个大表单需要几十个甚至一百个输入表单,但 React 是以可维护的方式建模你的 UI:你没有 100 个独立的输入字段,你有一组相关的输入,所以你捕获每个在一个组件中分组,然后将您的“主”表单构建为一组组。
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
这也比一个巨大的单一表单组件更容易维护。将组拆分为具有状态维护的组件,其中每个组件一次仅负责跟踪几个输入字段。
您可能还会觉得写出所有这些代码“很麻烦”,但这是一种错误的节省:不是您的开发人员,包括未来的您,实际上从看到所有这些输入明确连接起来后受益匪浅,因为它使代码路径更容易跟踪。但是,您始终可以优化。例如,您可以编写一个状态链接器
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});
当然,还有改进的版本,因此请访问 https://npmjs.com并搜索您最喜欢的 React 状态链接解决方案。开源主要是寻找其他人已经完成的工作,并使用它而不是自己从头开始编写所有内容。
React 16(和 15.5 过渡版)和“现代”JS
从 React 16(和 15.5 软启动)开始,createClass
不再支持调用,需要使用类语法。这改变了两件事:明显的类语法,还有可以“免费”执行的this
上下文绑定createClass
,因此为确保事情仍然有效,请确保您使用“粗箭头”表示法this
在onWhatever
处理程序中保留匿名函数的上下文,例如在onChange
这里的代码中,我们使用:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ''
};
}
render() {
return (
//...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
//...
);
},
updateInputValue(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
您可能还看到人们bind
在其构造函数中使用所有事件处理函数,如下所示:
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
不要那样做。
几乎在您使用 的任何时候bind
,谚语“您做错了”都适用。您的类已经定义了对象原型,因此已经定义了实例上下文。不要把bind
它放在首位;使用正常的事件转发,而不是在构造函数中复制所有函数调用,因为这种重复会增加您的错误面,并使跟踪错误变得更加困难,因为问题可能出在您的构造函数中,而不是您调用代码的位置。以及将维护负担置于您(必须或选择)与之合作的其他人身上。
是的,我知道react文档说这很好。不是,不要这样做。
React 16.8,使用带有钩子的函数组件
从 React 16.8 开始,函数组件(即实际上只是一个将 someprops
作为参数的函数可以用作组件类的实例,而无需编写类)也可以通过使用hooks来获得状态。
如果您不需要完整的类代码,而单个实例函数就可以,那么您现在可以使用useState
钩子为自己获取一个状态变量,及其更新函数,其工作原理与上述示例大致相同,只是没有“通用”setState
函数调用并为您正在处理的每个值使用一个专用状态设置器:
import { useState } from 'react';
function myFunctionalComponentFunction() {
const [input, setInput] = useState(''); // '' is the initial state value
return (
<div>
<label>Please specify:</label>
<input value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}
以前类和函数组件之间的非官方区别是“函数组件没有状态”,所以我们不能再躲在那个后面:函数组件和类组件之间的区别可以在很好的几页中找到- 编写的react文档(没有捷径可以方便地误解你!)你应该阅读它,这样你就知道你在做什么,从而知道你是否选择了最好的(无论对你来说意味着什么)解决方案来为你自己编程出于您遇到的问题。