React数据传递之组件内部通信的方法


Posted in Javascript onDecember 31, 2017

1. 概述

脱离初级前端一段时间后会发现,写样式的时间越来越少,处理数据的时间越来越多。处理数据的过程也就是实现业务逻辑的过程,这在项目中无疑是最重要的。

所以学习前端框架,了解完基本语法后,接下来就要学习其如何进行数据传递。

Angular 设计之初的一大亮点就是实现了数据的双向绑定,使用 Vue 一段时间后发现,所谓数据的双向绑定,组件内部唯一的应用场景就是 form 表单(input,textarea,select, radio),而这种场景下的数据双向绑定,即便框架内部没有实现,自己实现起来也非常简单。明白这一点后感觉之前认为 React 没有实现数据双向绑定很 low 的想法很幼稚。

对于 React 的数据传递,涉及两方面的内容:

  1. 组件内部的数据传递,典型的应用场景包括如何实现 form 表单双向数据绑定、如何绑定事件;
  2. 组件间的数据传递。 包括父组件往子组件传递数据、子组件往父组件传递数据以及兄弟组件之间传递数据。

本文先讨论组件内部的数据传递。

2. 组件内部数据传递

React 组件内部通信主要分为两部分:数据展示与事件处理。

2.1 数据展示

组件内部数据的展示和更新都是通过 state 来实现的,如果要使用 state 必须使用 ES6 的 class 定义组件。数据更新在双向数据绑定部分探讨,这部分仅讨论展示初始化数据。

如果你熟悉 Vue,React 的 state 对象相当于 Vue 的 data 对象

下面是一个纯展示数据的示例:

class App extends Component {
 constructor(props) {
 super(props);

 // 初始化 state
 this.state = {
  inputValue: "test",
 };
 }

 render() {
 // 注意,在 react 中,DOM 元素是对象,所以使用‘()'包住 
 return (
  <div className="App">
  <p>{this.state.inputValue}</p>
  </div>
 );
 }
}

在通过 class 定义的 React 组件中,除了生命周期钩子函数, constructor() 和 render() 着两个方法也是自动执行的,先执行 constructor() ,执行 constructor() 的同时也是再为 render() 渲染 DOM 做数据准备。

实际上 constructor() 函数是组件生命周期中调用的第一个函数。

2.2 事件

2.2.1 与 DOM 中事件的异同

在 React 中处理事件和在 DOM 中处理事件类似,有两点不同:

  1. React 中通过驼峰命名法命名事件,而不是全是小写字母;
  2. 在 JSX 中直接传递函数作为事件处理程序,而不是字符串。

第 2 点不同有坑,后面细说

举个例子,HTML中的事件:

<button onclick="activateLasers()">
 Activate Lasers
</button>

React 中的事件:

// 因为 jsx 中'{}'里面代表函数表达式,
// 所以传递给 onClick 的实际是函数 activateLasers 的函数体部分,
// 因此需要指定 this 指向,不然会报错
<button onClick={activateLasers}>
 Activate Lasers
</button>

2.2.2 存在的坑

直接传递 function 作为 event handler 需要指定函数的执行环境,即需要手动绑定 this ,不然会报 this 为 undefined 的错。见下面的例子:

class App extends Component {
 constructor(props) {
 super(props);
 this.state = {
  isToggleOn: true,
 };

 // 手动绑定 this
 this.handleClick = this.handleClick.bind(this);
 }

 handleClick() {
 // 如果不在 constructor() 方法中手动绑定 this,直接将其作为事件处理程序 this 为 undefined
 console.log(this);

 this.setState(prevState => ({
  isToggleOn: !prevState.isToggleOn
 }));
 }

 render() {
 return (
  <div className="App">
  <button onClick={this.handleClick}>
   {this.state.isToggleOn ? "on" : "off"}
  </button>
  </div>
 );
 }
}

2.2.3 为什么会有坑

React 官网 说这个锅要 JS 原生语法来背,其实不尽然,React 实在 JS 语法早已确定的情况下设计了这样的事件系统,如果一定要有人站出来背锅,他们五五分吧。

1, JS原生语法存在的问题

JS语法中有这样的规则:如果将一个函数的函数体(没有 () )赋值给另一个变量,函数体内部的 this 指向可能会发生变化。会不会变化取决于函数和被赋值的变量是否处于同一个作用域(相同的执行环境)中,但实际使用中,将一个函数赋值给相同作用域的变量没有意义,那样的话直接使用那个函数就好,没必要在赋值给另一个变量。

this 指向不发生改变的没有意义的例子(为了方便说明,直接使用 var 操作符):

var fn = function () {
 console.log(this);
};

var a = fn;

fn(); // window
a(); // window
this 指向发生改变的例子:

var fn = function () {
 console.log(this);
};

// 将函数体赋值给一个对象的属性,函数执行时 this 和定义时指向不同
var o = {
 a: fn,
};

fn(); // window
o.a(); // o,即{a:f}

如果想要在将函数体赋值另一个变量的同时把原函数的 this 指向也一块赋值过去,就需要在赋值的过程中进行绑定 this 的操作,如下:

var fn = function () {
 console.log(this);
};

// fn 在赋值的同时将内部的 this 打包一块赋值给了 a
var o = {
 a: fn.bind(this),
};

fn(); // window
o.a(); // window

通常在将函数体赋值给变量的时候为了避免 this 出错,都会进行 绑定执行环境的操作 ,典型的例子是 var bindId = document.getElementById.bind(document)

2, JSX 存在的问题

因为 JSX 中 DOM 元素也是对象,给元素的属性赋值实际是给 DOM 元素对象的属性赋值,见下:

const element = (
 <button onClick={this.handleClick}>click me</button>
);

等同于

const element = {
 type: 'button',
 props: {
 onClick: this.handleClick,
 children: 'click me',
 },
};

这实际就是 将函数体赋值给一个对象的属性,函数执行时 this 和定义时指向不同 的场景,和原生语法相同的是 this 指向发生了改变,不同的是原生 JS 中不管怎样, this 总归是有个指向的,而 JSX 直接 undefined 。

所以说不绑定 this 报 undefined 的错不能全怪 JS 原生语法。

3. 双向数据绑定

通过 state 传递数据加上事件处理程序便能实现数据的双向绑定,其背后的思想是(以 input 为例):初始化时将 state 中预定义的 state a 赋值给 input,当 input 的 value 发生改变时,触发事件处理程序,将改变后的 value 赋值给状态 a ,React 监测到 state 改变时重新调用 render() 方法,即重新渲染组件,达到双向绑定的目的。

class App extends Component {
 constructor(props) {
  super(props);
  this.state = {
   inputValue: "test",
  };
  this.changeInput = this.changeInput.bind(this);
 }

 changeInput(e) {
  // 将改变后的 input 值赋值给 inputValue,通过事件对象 $event.target.value 实现
  this.setState({
   inputValue: e.target.value
  });
 }

 render() {
  // input 改变时触发 changeInput
  return (
   <div className="App">
    <input value={this.state.inputValue} onChange={this.changeInput} />
    <p>{this.state.inputValue}</p>
   </div>
  );
 }
}

这里用到了事件对象,React 的事件对象和 JS 原生事件对象保持一致。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JQuery通过Ajax提交表单并返回结果
Jul 31 Javascript
仿JQuery输写高效JSLite代码的一些技巧
Jan 13 Javascript
jquery实现带缩略图的全屏图片画廊效果实例
Jun 25 Javascript
微信小程序 PHP后端form表单提交实例详解
Jan 12 Javascript
又一款MVVM组件 构建自己的Vue组件(2)
Mar 13 Javascript
ionic+AngularJs实现获取验证码倒计时按钮
Apr 22 Javascript
elementUI select组件默认选中效果实现的方法
Mar 25 Javascript
微信小程序在其他页面监听globalData中值的变化
Jul 15 Javascript
Vue.js标签页组件使用方法详解
Oct 19 Javascript
js实现课堂随机点名系统
Nov 21 Javascript
使用webpack5从0到1搭建一个react项目的实现步骤
Dec 16 Javascript
JavaScript+HTML实现学生信息管理系统
Apr 20 Javascript
javascript 通过键名获取键盘的keyCode方法
Dec 31 #Javascript
vue vuex vue-rouert后台项目——权限路由(适合初学)
Dec 29 #Javascript
Angular实现的内置过滤器orderBy排序与模糊查询功能示例
Dec 29 #Javascript
Angular实现的敏感文字自动过滤与提示功能示例
Dec 29 #Javascript
Angular实现点击按钮控制隐藏和显示功能示例
Dec 29 #Javascript
js实现手机web图片左右滑动效果
Dec 29 #Javascript
详解react-router 4.0 下服务器如何配合BrowserRouter
Dec 29 #Javascript
You might like
递归删除一个节点以及该节点下的所有节点示例
2014/03/19 PHP
Symfony2 session用法实例分析
2016/02/04 PHP
PHP基于curl post实现发送url及相关中文乱码问题解决方法
2017/11/25 PHP
js控制分页打印、打印分页示例
2014/02/08 Javascript
javascript鼠标滑动评分控件完整实例
2015/05/13 Javascript
js设置document.domain实现跨域的注意点分析
2015/05/21 Javascript
解决JS请求服务器gbk文件乱码的问题
2015/10/16 Javascript
全面解析Bootstrap表单使用方法(表单样式)
2015/11/24 Javascript
Bootstrap每天必学之附加导航(Affix)插件
2016/04/25 Javascript
JavaScript注入漏洞的原理及防范(详解)
2016/12/04 Javascript
js判断手机号是否正确并返回的实现代码
2017/01/17 Javascript
详解AngularJS 路由 resolve用法
2017/04/24 Javascript
angular实现图片懒加载实例代码
2017/06/08 Javascript
Vue实现移动端左右滑动效果的方法
2018/11/27 Javascript
vuex 动态注册方法 registerModule的实现
2019/07/03 Javascript
JavaScript碰撞检测原理及其实现代码
2020/03/12 Javascript
决策树的python实现方法
2014/11/18 Python
初步介绍Python中的pydoc模块和distutils模块
2015/04/13 Python
python输出当前目录下index.html文件路径的方法
2015/04/28 Python
AI人工智能 Python实现人机对话
2017/11/13 Python
Python大数据之使用lxml库解析html网页文件示例
2019/11/16 Python
CSS3 rgb and rgba(透明色)的使用详解
2020/09/25 HTML / CSS
kmart凯马特官网:美国最大的打折零售商和全球最大的批发商之一
2016/11/17 全球购物
万豪国际住宅与别墅集团:Homes & Villas by Marriott International
2020/10/08 全球购物
英国珠宝网站Argento: PANDORA、Olivia Burton和Nomination等
2020/05/08 全球购物
人力资源管理专业毕业生自我评价
2013/09/21 职场文书
毕业生个人的求职信范文
2013/12/03 职场文书
机械设计毕业生自荐信
2014/02/02 职场文书
渡河少年教学反思
2014/02/12 职场文书
地震捐款倡议书
2014/08/29 职场文书
2015年女生节活动总结
2015/02/27 职场文书
交心谈心活动总结
2015/05/11 职场文书
本科毕业论文答辩稿
2015/06/23 职场文书
Nginx优化服务之网页压缩的实现方法
2021/03/31 Servers
Python连续赋值需要注意的一些问题
2021/06/03 Python
浅谈 JavaScript 沙箱Sandbox
2021/11/02 Javascript