@[toc]
表单
在React中,HTML表单元素的工作方式与其他DOM元素不同,因为表单元素通常维护一些内部状态。例如,此纯HTML表单只接受一个名称:
<form>
<label>
名字:
<input type="text" name="name" />
</label>
<input type="submit" value="提交" />
</form>
此表单具有默认的HTML表单行为,即在用户提交表单后浏览到一个新页面。如果在React中执行相同的代码,它仍然有效。然而,在大多数情况下,使用JavaScript函数来处理表单提交以及访问用户填写的表单数据是非常方便的。实现这种效果的标准方法是使用“受控组件”。
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('提交的名字: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
名字:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
由于value属性是在表单元素上设置的,因此显示的值将始终为this。state Value,这使得React的状态成为唯一的数据源。因为handlechange在每次按下键时都会执行并更新React的状态,所以显示的值将在用户输入时更新。
class EssayForm extends React.Component {
constructor(props) {
super(props);
this.state = {
value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('提交的文章: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
文章:
<textarea value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="提交" />
</form>
);
}
}
对于受控组件,输入值始终由React状态驱动。您还可以将值传递给其他UI元素,或通过其他事件处理函数重置它,但这意味着您需要编写更多代码。
select
在HTML中,<select>
创建一个下拉列表标记。例如,以下HTML创建了一个与水果相关的下拉列表:
<select>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option selected value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
请注意,由于选定的属性,默认情况下会选择椰子选项。React不使用所选属性。相反,它使用根选择标记上的value属性。这在受控组件中更方便,因为您只需要在根标记中更新它。
class FlavorForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: 'coconut'};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('你喜欢的风味是: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
选择你喜欢的风味:
<select value={this.state.value} onChange={this.handleChange}>
<option value="grapefruit">葡萄柚</option>
<option value="lime">酸橙</option>
<option value="coconut">椰子</option>
<option value="mango">芒果</option>
</select>
</label>
<input type="submit" value="提交" />
</form>
);
}
}
状态提升
通常,多个组件需要反映相同的更改数据。此时,我们建议将共享状态提升到最近的公共父组件。让我们看看它是如何工作的。
function BoilingVerdict(props) {
if (props.celsius >= 100) {
return <p>The water would boil.</p>;
}
return <p>The water would not boil.</p>;
}
在本节中,我们将创建一个温度计算器来计算水在给定温度下是否沸腾。
我们将从一个名为BoilingVerdict的组件开始,它接受摄氏温度作为一个参数,并打印温度是否足以使水沸腾的结果。
class Calculator extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {temperature: ''};
}
handleChange(e) {
this.setState({temperature: e.target.value});
}
render() {
const temperature = this.state.temperature;
return (
<fieldset>
<legend>Enter temperature in Celsius:</legend>
<input
value={temperature}
onChange={this.handleChange} />
<BoilingVerdict
celsius={parseFloat(temperature)} />
</fieldset>
);
}
}
接下来,我们创建一个名为Calculator的组件。它为输入温度渲染一个<input>,并将其值保存在其中。状态温度。
此外,它还基于当前输入值渲染BoilingVerdict组件。
上述两个函数仅执行数值转换。相反,我们将编写另一个函数,接受字符串类型的温度和转换函数作为参数并返回字符串。我们将使用它根据另一个输入框的值来计算一个输入盒的值。
当输入温度值无效时,函数返回空字符串;否则,返回保留三位小数并四舍五入的转换结果:
我们现在有两个输入框,但当您在其中一个输入框中输入温度时,另一个将不会更新。这与我们的要求相矛盾:我们希望它们保持同步。
此外,我们无法通过Calculator组件显示BoingVerdict组件的渲染结果。因为计算器组件不知道TemperatureInput组件中隐藏的当前温度。
function tryConvert(temperature, convert) {
const input = parseFloat(temperature);
if (Number.isNaN(input)) {
return '';
}
const output = convert(input);
const rounded = Math.round(output * 1000) / 1000;
return rounded.toString();
}
但是,我们希望两个输入框中的值彼此同步。当我们更新摄氏度输入框中的值时,华氏度输入框应显示转换后的华氏温度,反之亦然。
在React中,要在多个组件之间共享的状态可以通过将其移动到最近的公共父组件来共享。这被称为“国家提升”。接下来,我们将把TemperatureInput组件中的状态移动到Calculator组件。
render() {
// Before: const temperature = this.state.temperature;
const temperature = this.props.temperature;
// ...
如果计算器组件具有共享状态,它将成为两个温度输入框中当前温度的“数据源”。它可以使两个温度输入框的值彼此一致。由于两个TemperatureInput组件的道具来自公共父组件Calculator,因此两个输入框的内容始终一致。