Reactjs入门官方文档(八)【forms】
2017-11-15 11:13
501 查看
表单
译自reactjs官方文档HTML 表单元素与 React 中的其他 DOM 元素有所不同,因为表单元素自然地保留了一些内部状态。例如,这个纯 HTML 表单接受一个单独的 name:
<form> <label> Name: <input type="text" name="name"/> </label> <input type="submit" value="Submit"/> </form>
该表单和 HTML 表单的默认行为一致,当用户提交此表单时浏览器会打开一个新页面。如果你希望 React 中保持这个行为,也可以工作。但是多数情况下,用一个处理表单提交并访问用户输入到表单中的数据的 JavaScript 函数也很方便。实现这一点的标准方法是使用一种称为“受控组件(controlled components)”的技术。
受控组件(Controlled Components)s
在HTML 中,像<input>、
<textarea>和
<select>这些form elements 通常保留它们自己的状态并根据用户输入来更新。在React 中,可变状态(mutable state)通常保存在组件的状态属性中(state property of components),并且只能由
setState()更新。
我们可以结合两方面来使React state 成为 “单一数据源原则”(single source of truth)。然后React 组件渲染form 同时也能控制后续的用户的输入。一个input 表单元素的值通过React 这种方式控制称为“受控组件”(controlled component)。
例如,如果我们想要在之前例子提交之前输出name,我们可以这样写一个form 作为controlled component:
class NameForm extends 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('A name was submitted: ' + this.state.value) event.preventDefault() } render(){ return ( <form onSubmit={this.handleSubmit}> <label> Name: <input type="text" name="name" value={this.state.value} onChange={this.handleChange}/> </label> <input type="submit" value="Submit"/> </form> ) } }
在CodePen 上尝试
由于
value特性(attribute)设置在form element,将总是展示
this.state.value这个值,使React state 成为同一数据理念(the source of truth)。由于
handleChange总是随着每一次按键而运行去更新React state,展示的值也总是随着用户的键入而更新。
对于controlled component,每一次状态改变(state mutation)总是有相应的句柄处理函数(handler function)。这能更直接的修改和验证用户的输入。例如,如果我们想强制将每一个输入都变成大写,我们可以如下修改
handleChange:
handleChange(event){ this.setState({ value: event.target.value.toUpperCase() }) }
textare 标签
在 HTML 中,<textarea>元素通过它的子节点定义了它的文本值:
<textarea> Hello there, this is some text in a text area </textarea>
在React 中,
<textarea>通过使用
value特性(attribute)来替代。这种方式使用
<textarea>在写法上非常类似form 使用单行输入(single-line input):
class EssayForm extends Component { constructor(props){ super(props) this.state = { value : 'Please write an essay about your favourite DOM element' } this.handleChange = this.handleChange.bind(this) this.handleSubmit = this.handleSubmit.bind(this) } handleChange(event){ this.setState({ value: event.target.value }) } handleSubmit(event){ alert('An essay was submitted: ' + this.state.value) event.preventDefault() } render(){ return ( <form onSubmit={this.handleSubmit}> <label> Name: <textarea value={this.state.value} onChange={this.handleChange} /> </label> <input type="submit" value="Submit"/> </form> ) } }
注意
this.state.value是在构造函数(constructor)中被初始化,所以这个文本域(text area)是以这里的文本为默认值的。
select 标签
在 HTML 中,<select>创建了一个下拉列表。例如,这段 HTML 创建一个下拉的口味(flavors)列表:
<select> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut" selected>Coconut</option> <option value="mango">Mango</option> </select>
注意到由于
selected特性(attibute),Coconut 选项是初始化被选中的。在React 中通过在根
select标签上使用
value特性(attribute)来替代使用
selected特性(attibute)。这对于controlled component 来说更方便,因为你只需要更新这一个位置就可以了。例如:
class FlavorForm extends 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('Your favourite flavor is: ' + this.state.value) event.preventDefault(); } render(){ return ( <form onSubmit={this.handleSubmit} > <label> Pick your favourite La Croix flavor <select value={this.state.value} onChange={this.handleChange}> <option value="grapefruit">Grapefruit</option> <option value="lime">Lime</option> <option value="coconut">Coconut</option> <option value="mango">Mango</option> </select> </label> <input type="submit" value="Submit"/> </form> ) } }
在CodePen 上尝试
总的来说,这使得
<input type="text>、
<textarea>
<select>的使用非常相似-它们都可以通过接受一个
value来实现controlled component。
处理多个输入元素
当你需要处理多个controlledinputelements,你可以添加一个
name特性(attibute)到每一个element,并且让句柄函数(handler function)根据
event.target.name的值去选择做什么。
例如:
class Reservation extends React.Component { constructor(props) { super(props) this.state = { isGoing: true, numberOfGuests: 2 } this.handleInputChange = this.handleInputChange.bind(this) } handleInputChange(event) { const target = event.target const value = target.type === 'checkbox' ? target.checked : target.value const name = target.name this.setState({ [name]: value }) } render() { return ( <form> <label> Is going: <input name="isGoing" type="checkbox" checked={this.state.isGoing} onChange={this.handleInputChange} /> </label> <br /> <label> Number of guests: <input name="numberOfGuests" type="number" value={this.state.numberOfGuests} onChange={this.handleInputChange} /> </label> </form> ) } }
在CodePen 上尝试
注意我们如何使用ES6computed property name语法更新state key 响应给定的input name:
this.setState({ [name]: value })
这段代码等价于 ES5 代码:
var partialState = {} partialState[name] = value this.setState(partialState)
此外,由于
setState()自动将部分状态合并到当前状态,所以我们只需要调用更改的部分。
受控组件的替代方案
有时使用controlled component 是非常令人厌烦的,因为你必须写事件句柄(event handler)为每一次你的数据改变和通过React component 来传递输入状态(input state)。尤其是在你改变之前的代码到React 或者在非React(non-React)库中使用React。在这些情况下,你可能想要符合uncontrolled components,一个替代实现input form 的技术。相关文章推荐
- Reactjs入门官方文档(十一)【Thinking in React】
- Reactjs入门官方文档(四)【state-and-lifecycle】
- Reactjs入门官方文档(五)【handling-events】
- Reactjs入门官方文档(六)【conditional-rendering】
- Reactjs入门官方文档(一)【jsx】
- Reactjs入门官方文档(二)【rendering-elements】
- Reactjs入门官方文档(七)【lists-and-keys】
- Reactjs入门官方文档(九)【lifting-state-up】
- React官方文档笔记之快速入门
- React.js 官方文档摘记:非受控组件
- part2 react官方文档笔记09--JSX In Depth
- React.js 官方文档翻译
- React.js 官方文档翻译2
- React.js 官方文档摘记:表单
- React.js 官方文档翻译3 代码集合
- React官方文档--Forms
- 官方文档reactJS实例,最终版
- vue.js从入门到放弃2--官方文档阅读笔记
- React官方文档—3.JSX 简介
- Qt元类型(MetaType)注册入门(附一些官方文档的关键摘录)