react入门教程二

react事件

由于react的虚拟DOM模式,react对所有的事件也都做了专门的处理和优化,官方的说法是引入了虚拟事件对象,将浏览器的事件进行了封装,有着浏览器本地事件西安通的属性和方法,但是没有兼容问题。听起来不错,回到我们之前state的demo,handleClick(e){}加一个console.log(e)来打印一下这个点击事件:

5

这里可以看到我们打印出来的全部是空,这是因为react给我们做了处理,把不需要的值全部隐藏了。现在我们来改一下console.log(e.target) :

6

可以看到target已经被打印出来了。如果你有时候需要的是本地的event的话可以使用e.nativeEvent来调用:

7

这里就是浏览器原生的event事件,但是需要注重浏览器兼容性。所以一般情况下最好使用react封装好的event事件,react支持的完整事件列表可以在官方文档查看,这里不再一一列举。

tip:如果需要阻止默认的事件,比如form表单的默认提交,a标签的href... 必须使用e.preventDefault() 。而需要阻止事件冒泡则需使用e.stopPropagation()。

React事件机制不同于我们以往的js事件,为提高效率,它对事件做了二次处理,将所有项目中注册的事件全部代理(delegate)到顶层的document上,当你点击某个DOM的时候,它会找到这个DOM和其Component,并冒泡到找到对应的事件并触发。

比如我们经典的 ul li 结构,传统js使用事件委托将事件绑定在ul上,而现在使用react只需要在ul上绑一个click事件,每次点击ul里面的元素都会冒泡并触发到ul的事件上去。但是要注意如果你在ul里面再绑定一个事件,同时不使用stopPropagation去阻止这个冒泡事件,那他会一直执行到最顶层的事件上去。

想要深入了解React事件机制?相信这篇博客会对你有所帮助——React源码解读系列 -- 事件机制

Refs & 真实DOM

由于react使用虚拟DOM的结构,所有的页面变动都先在虚拟DOM上处理,只有当他们真正插入到文档中才会转化成真实DOM,react正是通过这样的机制来减少DOM操作从而提高页面的性能。

但是有时候我们确实有获取DOM的需求,前面在学习事件的时候我们使用e.target可以获取到真实的DOM。

而同时react也给我们提供了refs 来处理类似的情况。ref在react中是一个特殊的属性,它可以是一个回调函数也可以是一个字符串。如果你查找国内的资料你会发现几乎所有人用的都是ref的字符串属性,但是在最新版(V15.4.2)的react文档中,ref的字符串属性被称为’Legacy API‘ ,官方强调字符串的ref存在一些问题,并且很可能在未来的版本中将其移除。

我们先来看一下官方的demo:

var MyComponent = React.createClass({
  handleClick: function() {
    this.textInput.focus();
    console.log(this);
    console.log(this.textInput)
  },
  render: function() {
    return (
      <div>
        <input type="text" ref={(input) => { this.textInput = input; }} />
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

ref的回调函数会在组件创建或者重新渲染时立即执行,回调函数的参数即为当前组件的真实DOM,我们可以立即使用这个DOM或者将其保存以备后用。

上面代码中输入框的ref使用es6语法直接在组件中创建了一个回调函数,这个函数将参数input保存到this.textInput中,我这里把 this 和 this.textInput 打印出来来帮助大家更好去理解:

8

这里this指向ReactElement,即当前的的react组件,通过回调函数往this里添加了textInput对象。通过下面的this.textInput就可以看到textInput为该组件的原生DOM,我们通过ref的回调函数将该DOM存在this中,方便后面随时调用。

简单的ref回调我们可以直接写在标签中,如果复杂的话我们可以将其抽出为一个函数,在标签中通过 ref={this.funtionName} 的形式调用。

同时我这里也有一个string refs的demo,虽然现在有很多人这样用,但是我们要尽量避免这样的写法:

var MyComponent = React.createClass({
  handleClick: function() {
    this.refs.myTextInput.focus();
  },
  render: function() {
    return (
      <div>
        <input type="text" ref="myTextInput" />
        <input type="button" value="Focus the text input" onClick={this.handleClick} />
      </div>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

这里给ref定义一个字符串,通过refs获取到页面所有的ref,再通过ref的字符串定位到该DOM,这样操作确实方便很多,所以这个方法被广为流传,但是建议有使用这样方法的童鞋最好慢慢抛弃这种写法。

tips:有些童鞋可能网上查找资料会看到getDOMNode() or findDOMNode() 方法,在早期react中确实存在这些方法结合ref来获取DOM,但是后来React拆分出ReactDOM后这些方法被归到ReactDOM 的方法中,直接在react中是不能使用的。

react表单

在开始之前我们先看一个例子:

var Form = React.createClass({
  render: function() {
    return (
      <input type='text' value='这是一个输入框'/>
    )
  }
})
ReactDOM.render(
  <Form/>,
  document.getElementById('example')
);

乍一看是不是和我们平时HTML的写法基本一样,但是一运行你就会发现无论如何你改变不了input中的值,键盘的输入对它没有任何影响!

react官方将带有value的表单定义为受限组件 ,即该组件受限制于value值,他将永远等于value的值。当然,不代表我们就不能定义表单的默认值了,官方给出了两种解决办法:

1,使用defaultValue。既然有受限组件,那就存在不受限组件。官方定义为不设置value的组件就是一个不受限组件,而不受限组件可以实时响应用户的输入将其反映到元素上。所以react就给组件定义了defaultValue来给组件设置一个非空的初始值,而对于radio,checkbox则有对应的defaultCheckd属性来代替checkd:

 <input type='text' defaultValue='这里是默认值,也可以使用state'/>

我们可以给input定义ref的回调来获取输入的值:

 <input type='text' ref={(input) => { this.textInput = input; }} defaultValue='这里是默认值,也可以使用state'/>

然后通过事件获取this.textInput.value。

比如我们一个页面有很多输入框,可以给他们分别定义ref,然后通过submit按钮的提交事件来一次性全部获取所有的输入值。

tip:如果我们需要阻止默认的表单提交事件,需要使用e.preventDefault(),这一点我们在之前的事件里提到过。 ( ) => { } 为ES6语法,它表示为 function( ) { }

2,对于使用state来给组件设置初始值的,可以给组件绑定onChange事件,通过onChange来实时获取用户输入,动态的改变state的值。这样虽然组件受限于value,但是value的值发生了变化,那么组件的值也就跟着变化:

var Form = React.createClass({
  getInitialState:function(){
    return {
        inputValue: 'input',
    }
  },
  handleInput:function(e) {
    this.setState({inputValue: e.target.value});
  },
  render: function() {
    return (
      <input type='text' value={this.state.inputValue} onChange={this.handleInput}/>
    )
  }
})
ReactDOM.render(
  <Form/>,
  document.getElementById('example')
);

以上是使用e.target.value来获取输入值来刷新state,当然你也可以使用ref来获取。

如果页面中有很多表单,但是我们又不想使用上面的defaultValue+ref,或者我们需要在用户输入的时候就获取输入值来检查。岂不是每一个表单组件都要定义一个onChange事件?

官方也考虑到这种问题,所以给我们提供了一个更好的解决方案:

var MyComponent = React.createClass({
  getInitialState: function() {
    return {
      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: function() {
    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>
    );
  }
});

ReactDOM.render(
  <MyComponent />,
  document.getElementById('example')
);

通过一个onChange事件来解决所有的表单,是不是很酷!

tip: [name] 为ES6语法,它表示在对象中,name为一个变量。

tip:<textarea> 常规设置默认值采用 <textarea>这里是默认值</textarea><select> 常规设置默认值是在 <option> 中添加selected,而这对于React来说会显得很奇怪,且不方便在后续的使用中来更新默认值。所以React中所有表单的默认值设置全部使用value(defaultValue)来定义,详细说明参见官方文档

生命周期

组件的生命周期分为三种:

  • Mounting:已插入真实 DOM
  • Updating:正在被重新渲染
  • Unmounting:已移出真实 DOM

react为每个状态提供两种处理函数,will在函数状态之前调用,did则在函数状态之后调用:

  • componentWillMount()
  • componentDidMount()
  • componentWillUpdate(object nextProps, object nextState)
  • componentDidUpdate(object prevProps, object prevState)
  • componentWillUnmount()

此外还有三种特殊状态的处理函数:

  • constructor():组件调用之前的构造函数,早于componentWillMount(),常用于声明props和state
  • componentWillReceiveProps(object nextProps):已加载组件收到新的参数时调用
  • shouldComponentUpdate(object nextProps, object nextState):组件判断是否重新渲染时调用
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容

  • It's a common pattern in React to wrap a component in an ...
    jplyue阅读 3,191评论 0 2
  • 深入JSX date:20170412笔记原文其实JSX是React.createElement(componen...
    gaoer1938阅读 7,981评论 2 35
  • 原教程内容详见精益 React 学习指南,这只是我在学习过程中的一些阅读笔记,个人觉得该教程讲解深入浅出,比目前大...
    leonaxiong阅读 2,770评论 1 18
  • 以下内容是我在学习和研究React时,对React的特性、重点和注意事项的提取、精练和总结,可以做为React特性...
    科研者阅读 8,106评论 2 21
  • 本笔记基于React官方文档,当前React版本号为15.4.0。 1. 安装 1.1 尝试 开始之前可以先去co...
    Awey阅读 7,532评论 14 128