表单在React里的高级运用和select状态提升【高级React技术】

简介: 表单在React里的高级运用和select状态提升【高级React技术】

@[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,因此两个输入框的内容始终一致。

相关文章
|
4月前
|
开发框架 Dart 前端开发
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
【4月更文挑战第30天】对比 Flutter(Dart,强类型,Google支持,快速热重载,高性能渲染)与 React Native(JavaScript,庞大生态,热重载,依赖原生渲染),文章讨论了开发语言、生态系统、性能、开发体验、学习曲线、社区支持及项目选择因素。两者各有优势,选择取决于项目需求、团队技能和长期维护考虑。参考文献包括官方文档和性能比较文章。
200 0
【Flutter前端技术开发专栏】Flutter与React Native的对比与选择
|
6天前
|
人工智能 前端开发 JavaScript
react js 处理表单( form )的2个例子
react js 处理表单( form )的2个例子
|
1月前
|
移动开发 前端开发 JavaScript
使用React Native进行跨平台移动开发:技术探索与实践
【8月更文挑战第10天】React Native以其跨平台、高性能、易学习等优势,在移动开发领域取得了显著的成果。通过合理使用React Native,开发者可以更加高效地开发出高质量、低成本的移动应用。然而,在享受React Native带来的便利的同时,我们也需要关注其潜在的挑战和限制,并通过不断学习和实践来提升我们的开发能力。
|
19天前
|
前端开发 Java Spring
Spring与Angular/React/Vue:当后端大佬遇上前端三杰,会擦出怎样的火花?一场技术的盛宴,你准备好了吗?
【8月更文挑战第31天】Spring框架与Angular、React、Vue等前端框架的集成是现代Web应用开发的核心。通过RESTful API、WebSocket及GraphQL等方式,Spring能与前端框架高效互动,提供快速且功能丰富的应用。RESTful API简单有效,适用于基本数据交互;WebSocket支持实时通信,适合聊天应用和数据监控;GraphQL则提供更精确的数据查询能力。开发者可根据需求选择合适的集成方式,提升用户体验和应用功能。
52 0
|
19天前
|
容器 Kubernetes Docker
云原生JSF:在Kubernetes的星辰大海中,让JSF应用乘风破浪!
【8月更文挑战第31天】在本指南中,您将学会如何在Kubernetes上部署JavaServer Faces (JSF)应用,享受容器化带来的灵活性与可扩展性。文章详细介绍了从构建Docker镜像到配置Kubernetes部署全流程,涵盖Dockerfile编写、Kubernetes资源配置及应用验证。通过这些步骤,您的JSF应用将充分利用Kubernetes的优势,实现自动化管理和高效运行,开启Java Web开发的新篇章。
35 0
|
19天前
|
Java 前端开发 Spring
技术融合新潮流!Vaadin携手Spring Boot、React、Angular,引领Web开发变革,你准备好了吗?
【8月更文挑战第31天】本文探讨了Vaadin与Spring Boot、React及Angular等主流技术栈的最佳融合实践。Vaadin作为现代Java Web框架,与其他技术栈结合能更好地满足复杂应用需求。文中通过示例代码展示了如何在Spring Boot项目中集成Vaadin,以及如何在Vaadin项目中使用React和Angular组件,充分发挥各技术栈的优势,提升开发效率和用户体验。开发者可根据具体需求选择合适的技术组合。
28 0
|
19天前
|
前端开发 JavaScript API
掌握React表单管理的高级技巧:探索Hooks和Context API如何协同工作以简化状态管理与组件通信
【8月更文挑战第31天】在React中管理复杂的表单状态曾是一大挑战,传统上我们可能会依赖如Redux等状态管理库。然而,React Hooks和Context API的引入提供了一种更简洁高效的解决方案。本文将详细介绍如何利用Hooks和Context API来优化React应用中的表单状态管理,通过自定义Hook `useForm` 和 `FormContext` 实现状态的轻松共享与更新,使代码更清晰且易于维护,为开发者带来更高效的开发体验。
25 0
|
19天前
|
缓存 前端开发 JavaScript
React.memo 与 useMemo 超厉害!深入浅出带你理解记忆化技术,让 React 性能优化更上一层楼!
【8月更文挑战第31天】在React开发中,性能优化至关重要。本文探讨了`React.memo`和`useMemo`两大利器,前者通过避免不必要的组件重渲染提升效率,后者则缓存计算结果,防止重复计算。结合示例代码,文章详细解析了如何运用这两个Hook进行性能优化,并强调了合理选择与谨慎使用的最佳实践,助你轻松掌握高效开发技巧。
35 0
|
19天前
|
前端开发 JavaScript 数据管理
React Formik入门:简化表单处理的神器——全面掌握Formik在React表单开发中的高效应用与实战技巧
【8月更文挑战第31天】在React应用中,表单处理常常因繁琐而令人头疼。Formik作为一个开源库,专为简化React表单设计,减少冗余代码并提升处理效率。本文介绍Formik的使用方法及其优势,通过示例展示如何安装配置并创建基本表单,帮助开发者轻松应对各种表单需求。
24 0
|
19天前
|
前端开发 UED 开发者
React.lazy()与Suspense:实现按需加载的动态组件——深入理解代码分割、提升首屏速度和优化用户体验的关键技术
【8月更文挑战第31天】在现代Web应用中,性能优化至关重要,特别是减少首屏加载时间和提升用户交互体验。React.lazy()和Suspense组件提供了一种优雅的解决方案,允许按需加载组件,仅在需要渲染时加载相应代码块,从而加快页面展示速度。Suspense组件在组件加载期间显示备选内容,确保了平滑的加载过渡。
30 0