事件处理
事件处理 – React (docschina.org)
需要传入一个函数作为事件处理函数,而不是一个字符串。
复制 < button onClick = {activateLasers}>
Activate Lasers
</ button >
不能通过返回 false
的方式阻止默认行为。必须显式的使用 preventDefault
。
复制 function ActionLink () {
function handleClick (e) {
e .preventDefault ();
console .log ( 'The link was clicked.' );
}
return (
< a href = "#" onClick = {handleClick}>
Click me
</ a >
);
}
使用 React 时,你一般不需要使用 addEventListener
为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。将事件处理函数声明为 class 中的方法。
复制 class Toggle extends React . Component {
constructor (props) {
super (props);
this .state = {isToggleOn : true };
// 为了在回调中使用 `this`,这个绑定是必不可少的
this .handleClick = this . handleClick .bind ( this );
}
handleClick () {
this .csetState (state => ({
isToggleOn : ! state .isToggleOn
}));
}
render () {
return (
< button onClick = { this .handleClick}>
{ this . state .isToggleOn ? 'ON' : 'OFF' }
</ button >
);
}
}
ReactDOM .render (
< Toggle /> ,
document .getElementById ( 'root' )
);
列表与key
列表 & Key – React (docschina.org)
key
key 帮助 React 识别哪些元素改变了,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。
一个元素的 key 最好是这个元素在列表中拥有的一个独一无二的字符串。通常,我们使用数据中的 id 来作为元素的 key
key 只是在兄弟节点之间必须唯一
数组元素中使用的 key 在其兄弟节点之间应该是独一无二的。然而,它们不需要是全局唯一的。当我们生成两个不同的数组时,我们可以使用相同的 key 值
表单
表单 – React (docschina.org)
在 React 里,HTML 表单元素的工作方式和其他的 DOM 元素有些不同,这是因为表单元素通常会保持一些内部的 state。
受控组件
在 HTML 中,表单元素(如<input>
、 <textarea>
和 <select>
)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()
来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源” 。渲染表单的 React 组件 还控制 着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
textarea 标签
在 HTML 中, <textarea>
元素通过其子元素定义其文本:
复制 < textarea >
你好, 这是在 text area 里的文本
</ textarea >
而在 React 中,<textarea>
使用 value
属性代替。这样,可以使得使用 <textarea>
的表单和使用单行 input 的表单非常类似:
复制 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 >
);
}
}
请注意,this.state.value
初始化于构造函数中,因此文本区域默认有初值。
状态提升
通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。让我们看看它是如何运作的。
状态提升 – React (docschina.org)
我们将从一个名为 BoilingVerdict
的组件开始,它接受 celsius
温度作为一个 prop,并据此打印出该温度是否足以将水煮沸的结果。
复制 function BoilingVerdict (props) {
if ( props .celsius >= 100 ) {
return < p >The water would boil.</ p >; }
return < p >The water would not boil.</ p >;}
接下来, 我们创建一个名为 Calculator
的组件。它渲染一个用于输入温度 的 <input>
,并将其值保存在 this.state.temperature
中。
另外, 它根据当前输入值渲染 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
组件中抽离出 TemperatureInput
组件,然后为其添加一个新的 scale
prop,它可以是 "c"
或是 "f"
:
复制 const scaleNames = { c : 'Celsius' , f : 'Fahrenheit' };
class TemperatureInput 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;
const scale = this . props .scale; return (
< fieldset >
< legend >Enter temperature in {scaleNames[scale]}:</ legend > < input value = {temperature}
onChange = { this .handleChange} />
</ fieldset >
);
}
}
我们现在可以修改 Calculator
组件让它渲染两个独立的温度输入框组件:
我们先从 Calculator
组件中抽离出 TemperatureInput
组件,然后为其添加一个新的 scale
prop,它可以是 "c"
或是 "f"
:
在 React 应用中,任何可变数据应当只有一个相对应的唯一“数据源”。通常,state 都是首先添加到需要渲染数据的组件中去。然后,如果其他组件也需要这个 state,那么你可以将它提升至这些组件的最近共同父组件中。你应当依靠自上而下的数据流 ,而不是尝试在不同组件间同步 state。
虽然提升 state 方式比双向绑定方式需要编写更多的“样板”代码,但带来的好处是,排查和隔离 bug 所需的工作量将会变少。由于“存在”于组件中的任何 state,仅有组件自己能够修改它,因此 bug 的排查范围被大大缩减了。此外,你也可以使用自定义逻辑来拒绝或转换用户的输入。