React教程第25部分:表单研讨会

在React培训课程的今天翻译中,邀请您完成表单任务。

图片

第1部分:课程概述,React,ReactDOM和JSX普及的原因
第2部分:功能组件
第3部分:组件文件,项目结构
第4部分:父级和子级组件
第5部分:TODO应用程序的开始工作,样式设计的基础
第6部分:关于本课程的一些功能,JSX和JavaScript
第7部分:内联样式
第8部分:继续研究TODO应用程序,熟悉组件的属性
第9部分:组件属性
第10部分:使用组件特性和样式的研讨会
第11部分:动态标记生成和映射数组方法
第12部分:研讨会,TODO应用程序的第三阶段工作
第13部分:基于类的组件
第14部分:关于基于类的组件,组件状态的研讨会
第15部分:组件健康研讨会
第16部分:TODO应用程序的第四阶段工作,事件处理
第17部分:TODO应用程序的第五阶段工作,修改组件的状态
第18部分:TODO应用程序的第六阶段工作
第19部分:组件生命周期方法
第20部分:条件渲染的第一课
第21部分:关于条件渲染的第二课​​和研讨会
第22部分:TODO应用程序的第七阶段工作,从外部资源下载数据
第23部分:关于使用表格的第一课
第24部分:第二形式课
第25部分:使用表单的研讨会
第26部分:应用程序体系结构,容器/组件模式
第27部分:课程项目

课43.讲习班。 处理表格


原创

▍工作


在本实践课程中,邀请您提出App组件的代码,该代码位于create-react-app创建的标准项目的App.js文件中。 这是代码:

 import React, {Component} from "react" class App extends Component {   constructor() {       super()       this.state = {}   }     render() {       return (           <main>               <form>                   <input placeholder="First Name" /><br />                   <input placeholder="Last Name" /><br />                   <input placeholder="Age" /><br />                                     {/*       */}                   <br />                                     {/*          */}                   <br />                                     {/*        */}                   <br />                                     <button>Submit</button>               </form>               <hr />               <h2><font color="#3AC1EF">Entered information:</font></h2>               <p>Your name: {/*    */}</p>               <p>Your age: {/*  */}</p>               <p>Your gender: {/*  */}</p>               <p>Your destination: {/*   */}</p>               <p>                   Your dietary restrictions:                   {/*    */}               </p>           </main>       )   } } export default App 

通常,您的任务是确保用户在使用表单控件时输入的数据立即显示在此表单下方的文本中。 完成任务时,请利用托管组件技术。 应该注意的是,提供给您的任务是任务的改编版,因此您可以对其进行研究,以更好地了解邀请您创建和配置的控件的功能。

这是组件现在在屏幕上显示的内容。


浏览器中的应用

▍解决方案


您可以从不同角度解决向您提出的问题的解决方案。 我们将从将所需的所有内容置于状态开始,然后设置组件的控件和其他机制。

此刻,组件的状态如下图所示。

 this.state = {   firstName: "",   lastName: "",   age: 0,   gender: "",   destination: "",   dietaryRestrictions: [] } 

有必要考虑以下事实:在处理程序的过程中,可能会发现,例如,更方便地进行不同的状态初始化。 如果遇到类似情况,将更改状态初始化代码。 尤其是,现在可能会由于age属性中写入的数字0(可能存储用户输入的年龄)而引起一些疑问。 也许有必要对标志数据存储系统进行其他操作,该系统现在由dietaryRestrictions属性表示,并由一个空数组初始化。

现在,在状态初始化之后,让我们来设置控件。 由于代码已经对输入字段进行了描述-让我们开始使用它们。

这些控件将需要通过设置其name属性来命名,以使其与状态属性的名称相匹配,状态属性的名称将存储在这些字段中输入的数据。 它们应具有value属性,其值是根据状态中存储的数据确定的。 在每个字段中输入数据时,需要将输入的数据传递给组件,这导致它们需要具有onChange事件onChange 。 所有这些考虑因素导致以下事实:现在对字段的描述如下所示:

 <input   name="firstName"   value={this.state.firstName}   onChange={this.handleChange}   placeholder="First Name" /> <br /> <input   name="lastName"   value={this.state.lastName}   onChange={this.handleChange}   placeholder="Last Name" /> <br /> <input   name="age"   value={this.state.age}   onChange={this.handleChange}   placeholder="Age" /> 

作为用于处理这些字段的onChange事件的方法, this.handleChange仍然不存在。 创建此方法:

 handleChange(event) {   const {name, value} = event.target   this.setState({       [name]: value   }) } 

在这里,我们从event.target对象中提取namevalue属性,然后使用它们来设置相应的状态属性。 目前,这样的通用事件处理程序代码将适合我们,但是稍后,当我们开始使用标志时,我们将对其进行更改。

不要忘记在组件构造函数中执行的this绑定:

 this.handleChange = this.handleChange.bind(this) 

为了在firstNamesecondNameage字段中输入的数据页面的底部实现输出, secondName将使用相应的<p>元素,使其具有以下格式:

 <p>Your name: {this.state.firstName} {this.state.lastName}</p> <p>Your age: {this.state.age}</p> 

现在,让我们看看我们得到了什么。


浏览器中的应用

如您所见,在用于输入年龄的字段中,未显示任何提示。 而是显示age的state属性中设置的值,即0。我们需要在空字段中提示。 让我们尝试用null代替state的age null 。 之后,事实证明该表单看起来应该是正确的,但是控制台中关于age字段显示以下警告:

 Warning: `value` prop on `input` should not be null. Consider using an empty string to clear the component or `undefined` for uncontrolled components 

结果,我们将需要用一个空字符串替换age state属性的值,将状态初始化代码转换为以下形式:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: [] } 

现在尝试表格。 打开后,其外观将与工作开始时的外观相同,即提示将返回到“ age字段。 填写字段时,输入的数据将显示在页面底部。


浏览器中的应用

如您所见,在工作的这个阶段,所有功能都按预期运行。

现在,我们将从事新的元素。 处理表单的下一步将是向其添加开关。

我们将开关包装在<label> ,这不仅使我们可以对开关进行签名,而且还可以确保单击此签名(即在其父元素上)导致对其进行选择。

使用开关时,要记住它们是带有checked属性的标志和具有value属性的文本字段的组合。 这些开关组成一个组,其中为每个开关分配相同的名称,并根据配置的条件设置开关的checked属性,这样就不可能打开多个开关(属于同一组)。 onChangeonChange开关的事件处理程序。

结果,开关描述代码将如下所示:

 <label>   <input       type="radio"       name="gender"       value="male"       checked={this.state.gender === "male"}       onChange={this.handleChange}   /> Male </label> <br /> <label>   <input       type="radio"       name="gender"       value="female"       checked={this.state.gender === "female"}       onChange={this.handleChange}   /> Female </label> 

现在,我们将处理位于页面底部的相应<p>元素,如下所示:

 <p>Your gender: {this.state.gender}</p> 

之后,可以测试表格。 启动后立即取消选择两个开关,因为状态存储在一个值中,该值不允许在将其checked属性设置为true时执行任何检查。 单击其中之一后,相应的值进入状态(存储在开关的value属性中),选中该开关,相应的文本显示在表单底部。


浏览器中的应用

现在让我们在组合框上工作。 他的工件如下所示:

 <select>   <option></option>   <option></option>   <option></option>   <option></option> </select> 

此代码表明我们计划描述一个包含四个项目的组合框。

<select>标记及其<option>标记具有value属性。 但是,这些属性具有不同的含义。 分配给<option>元素的值表示在选择此元素时相应的状态属性。 这些是应该在下拉列表中的行。 在我们的情况下,这些是某些目的地,例如国家/地区。 让我们用小写字母写出它们的名称,以便它们的外观与代码中其他元素的value属性的值相对应。 之后,组合框的代码将如下所示:

 <select value=>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

如果我们谈论<select>value属性,那么这里不会显示一些硬编码的值,而是指向相应的state属性的链接:

 <select value={this.state.destination}>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

为该字段分配其他属性。 特别是,与状态中的属性名称相对应的名称,以及onChange事件onChange this.handleChange

 <select   value={this.state.destination}   name="destination"   onChange={this.handleChange} >   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

现在,我们将配置<p>元素的描述,该描述将显示在destination字段中选择的内容:

 <p>Your destination: {this.state.destination}</p> 

如果您现在在浏览器中查看页面,您会看到在字段中自动选择了列表的第一个元素,但这显然不会导致状态更新,因为在Your destination:行中的冒号后面没有显示任何内容。


浏览器中的应用

为了使germany价值落入该状态,您需要打开组合框并首先选择其他内容,然后选择Germany

通常,为了考虑列表字段的此功能,在它们的列表中,作为第一个元素,他们放置了诸如带有空值的元素以及带有诸如-- Please Choose a destination --类的文本的东西。 在我们的情况下,可能看起来像这样:

 <select   value={this.state.destination}   name="destination"   onChange={this.handleChange} >   <option value="">-- Please Choose a destination --</option>   <option value="germany">Germany</option>   <option value="norway">Norway</option>   <option value="north pole">North Pole</option>   <option value="south pole">South Pole</option> </select> 

我们将专注于设置组合框的此选项。

现在,也许让我们处理与标志相关的任务中最困难的部分。 在这里值得dietaryRestrictions的是,计划用于标志的状态属性dietaryRestrictions是用空数组初始化的。 现在,在使用控件时,感觉最好将此字段表示为对象。 因此,使用以友好名称的该对象的属性形式而不是数组元素的形式表示单个标志的实体将更加方便。 对象的属性(现在将由dietaryRestrictions状态dietaryRestrictions )将包含布尔值,该布尔值指示是否清除了对应的复选框( false )或选中了( true )。 现在状态初始化代码将如下所示:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   dietaryRestrictions: {       isVegan: false,       isKosher: false,       isLactoseFree: false   } } 

如您所见,我们计划创建三个标志。 加载页面后,所有这些都将立即重置。

我们在组件返回的代码中描述这些标志,将它们包装在<label>标记中并设置其属性。 他们的代码如下所示:

 <label>   <input       type="checkbox"       name="isVegan"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isVegan}   /> Vegan? </label> <br /> <label>   <input       type="checkbox"       name="isKosher"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isKosher}   /> Kosher? </label> <br /> <label>   <input       type="checkbox"       name="isLactoseFree"       onChange={this.handleChange}       checked={this.state.dietaryRestrictions.isLactoseFree}   /> Lactose Free? </label> 

dietaryRestrictions对象的属性名称用作标志名称,而this.state.dietaryRestrictions.isSomething形式的this.state.dietaryRestrictions.isSomethingchecked属性的值。

请注意,尽管将现有的onChange指定为this.handleChange事件处理程序,但我们必须对程序进行一些更改以确保程序正常运行。

看一下应用程序。


浏览器中的应用

如您所见,页面上的标志已显示,但是该组件尚未包含确保其正常运行所需的所有机制。 让我们处理事件处理程序。

在这里,要使用标志,除了已经提取的那些属性之外,我们还需要从event.target对象中提取typechecked属性。 第一个需要检查元素的类型(标志是checkbox行所代表的类型),第二个需要找出复选框是选中还是未选中。 如果事实证明在用户与标志交互之后调用了处理程序,则我们使用特殊的状态设置过程。 我们将以与以前相同的方式处理其他控件的事件。

在更新状态时,应该牢记React是一个相当智能的系统,如果仅更新部分状态,它将自动在新状态中合并保持不变和更改的内容。 但是不能确定是否将以相同方式执行对象属性(即状态属性的值)的工作。 我们将把handleChange代码带到以下形式来验证这一点。 在这里,我们假设dietaryRestrictions对象的属性可以一次更改一次:

 handleChange(event) {   const {name, value, type, checked} = event.target   type === "checkbox" ?       this.setState({           dietaryRestrictions: {               [name]: checked           }       })   :   this.setState({       [name]: value   }) } 

如果您在浏览器中打开应用程序页面,则下载后立即看起来一切正常,例如,当您尝试在“ First Name字段中输入First Name ,一切都会像以前一样工作,但是当您尝试安装其中一个复选框时,将发出以下警告:
警告:组件正在将类型为受控的复选框更改为不受控制。 输入元素不应从受控状态切换到非受控状态(反之亦然)。 确定在组件的使用寿命期间使用受控或不受控制的输入元素。 更多信息: fb.me/react-control-components

为了正确更新dietaryRestrictions对象的内容,您可以使用setState函数形式自己创建状态的新版本。 如果我们必须管理大量标志,那么我们可能会这样做。 但是在这里我们将否则。 即,我们将使dietaryRestrictions对象的dietaryRestrictions属性成为属性,从而摆脱该对象:

 this.state = {   firstName: "",   lastName: "",   age: "",   gender: "",   destination: "",   isVegan: false,   isKosher: false,   isLactoseFree: false } 

现在,我们将更改标志属性的设置,以摆脱dietaryRestrictions

 <label>   <input       type="checkbox"       name="isVegan"       onChange={this.handleChange}       checked={this.state.isVegan}   /> Vegan? </label> <br /> <label>   <input       type="checkbox"       name="isKosher"       onChange={this.handleChange}       checked={this.state.isKosher}   /> Kosher? </label> <br /> <label>   <input       type="checkbox"       name="isLactoseFree"       onChange={this.handleChange}       checked={this.state.isLactoseFree}   /> Lactose Free? </label> 

最后,编辑显示用户指定饮食限制信息的元素代码:

 <p>Your dietary restrictions:</p> <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p> <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p> <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p> 

之后,我们将检查应用程序的运行状况。


浏览器中的应用

如您所见,一切正常。

这是App组件的完整代码:

 import React, {Component} from "react" class App extends Component {   constructor() {       super()       this.state = {           firstName: "",           lastName: "",           age: "",           gender: "",           destination: "",           isVegan: false,           isKosher: false,           isLactoseFree: false       }       this.handleChange = this.handleChange.bind(this)   }     handleChange(event) {       const {name, value, type, checked} = event.target       type === "checkbox" ?           this.setState({               [name]: checked           })       :       this.setState({           [name]: value       })   }     render() {       return (           <main>               <form>                   <input                       name="firstName"                       value={this.state.firstName}                       onChange={this.handleChange}                       placeholder="First Name"                   />                   <br />                                     <input                       name="lastName"                       value={this.state.lastName}                       onChange={this.handleChange}                       placeholder="Last Name"                   />                   <br />                                     <input                       name="age"                       value={this.state.age}                       onChange={this.handleChange}                       placeholder="Age"                   />                   <br />                                     <label>                       <input                           type="radio"                           name="gender"                           value="male"                           checked={this.state.gender === "male"}                           onChange={this.handleChange}                       /> Male                   </label>                                     <br />                                     <label>                       <input                           type="radio"                           name="gender"                           value="female"                           checked={this.state.gender === "female"}                           onChange={this.handleChange}                       /> Female                   </label>                                     <br />                                     <select                       value={this.state.destination}                       name="destination"                       onChange={this.handleChange}                   >                       <option value="">-- Please Choose a destination --</option>                       <option value="germany">Germany</option>                       <option value="norway">Norway</option>                       <option value="north pole">North Pole</option>                       <option value="south pole">South Pole</option>                   </select>                                     <br />                                     <label>                       <input                           type="checkbox"                           name="isVegan"                           onChange={this.handleChange}                           checked={this.state.isVegan}                       /> Vegan?                   </label>                   <br />                                     <label>                       <input                           type="checkbox"                           name="isKosher"                           onChange={this.handleChange}                           checked={this.state.isKosher}                       /> Kosher?                   </label>                   <br />                                     <label>                       <input                           type="checkbox"                           name="isLactoseFree"                           onChange={this.handleChange}                           checked={this.state.isLactoseFree}                       /> Lactose Free?                   </label>                   <br />                                     <button>Submit</button>               </form>               <hr />               <h2><font color="#3AC1EF">Entered information:</font></h2>               <p>Your name: {this.state.firstName} {this.state.lastName}</p>               <p>Your age: {this.state.age}</p>               <p>Your gender: {this.state.gender}</p>               <p>Your destination: {this.state.destination}</p>               <p>Your dietary restrictions:</p>                             <p>Vegan: {this.state.isVegan ? "Yes" : "No"}</p>               <p>Kosher: {this.state.isKosher ? "Yes" : "No"}</p>               <p>Lactose Free: {this.state.isLactoseFree ? "Yes" : "No"}</p>                         </main>       )   } } export default App 

总结


今天,您已经完成了表格上的实际工作。 然后,您重复了在以前的课程中学到的知识,我们希望您学到了一些新知识。 下次我们将讨论React应用程序的体系结构。

亲爱的读者们! 告诉我,完成这项实际工作难吗?

Source: https://habr.com/ru/post/zh-CN446208/


All Articles