React
React 是⼀个 申明式 ,⾼效且灵便的⽤于构建⽤户界⾯的 JavaScript 库。使⽤ React 能够将⼀ 些简短、独⽴的代码⽚段组合成简单的 UI 界⾯,这些代码⽚段被称作“ 组件”。
MVC 与 MVVM
- MVC
MVC 全名是 Model View Controller,是模型 (model)-视图(view)-控制器(controller) 的缩写,一种软件设计榜样,用一种业务逻辑、数据、界面显示拆散的办法组织代码,将业务逻辑汇集到一个部件外面,在改良和个性化定制界面及用户交互的同时,不须要从新编写业务逻辑。MVC 被独特的倒退起来用于映射传统的输出、解决和输入性能在一个逻辑的图形化用户界面的构造中。
这里次要讲的是 前端的 MVC 实现, 不要跟后端的 MVC 搞混了。它的目标是:
- 代码复用;
- 划分职责,不便前期保护;
Model(模型):负责保留利用数据,与后端数据进行同步
View(视图):负责视图展现,将 model 中的数据可视化
Controller(控制器):负责业务逻辑,依据用户行为对 Model 数据进行批改
// model
var myapp = {}; // 创立这个应⽤对象
myapp.Model = function() {
var val = 0;
this.add = function(v) {if (val < 100) val += v;
};
this.sub = function(v) {if (val > 0) val -= v;
};
this.getVal = function() {return val;};
/* 观察者模式 */
var self = this,
views = [];
this.register = function(view) {views.push(view);
};
this.notify = function() {for(var i = 0; i < views.length; i++) {views[i].render(self);
}
};
};
// view
myapp.View = function(controller) {var $num = $('#num'),
$incBtn = $('#increase'),
$decBtn = $('#decrease');
this.render = function(model) {$num.text(model.getVal() + 'rmb');
};
/* 绑定事件 */
$incBtn.click(controller.increase);
$decBtn.click(controller.decrease);
};
// controller
myapp.Controller = function() {
var model = null,
view = null;
this.init = function() {
/* 初始化 Model 和 View */
model = new myapp.Model();
view = new myapp.View(this);
/* View 向 Model 注册,当 Model 更新就会去告诉 View 啦 */
model.register(view);
model.notify();};
/* 让 Model 更新数值并告诉 View 更新视图 */
this.increase = function() {model.add(1);
model.notify();};
this.decrease = function() {model.sub(1);
model.notify();};
};
// init
(function() {var controller = new myapp.Controller();
controller.init();})();
- MVVM
MVVM:Model、View、ViewModel。
总结
- 这二者都是框架的设计模式,设计的目标都是为了解决 Model 和 View 的耦合问题
- MVC 呈现比拟早次要利用在后端,如 Spring MVC、ASP.NET MVC 等,在前端畛域晚期也有利用,如 Backbone.js。长处是分层清晰,缺点是数据流凌乱,灵活性带来的保护问题。
- MVVM 在前端畛域有广泛应用,它不仅解决了 MV 耦合问题,还同时解决了保护二者映射关系的大量繁冗代码和 DOM 操作代码,在进步开发效率、可读性同时还放弃了优越的性能体现。
JSX 语法
JSX 称为 JS 的语法扩大,将 UI 与逻辑层耦合在组件⾥,⽤ {} 标识
因为 JSX 语法上更靠近 JS ⽽不是 HTML,所以使⽤ camelCase(⼩驼峰命名)来定义属性的名称;JSX ⾥的 class 变成了 className,⽽ tabindex 则变为 tabIndex。
生命周期
由上图可知,React 16.8+ 的生命周期分为三个阶段,别离是 挂载阶段 、 更新阶段 、 卸载阶段。
当你应用生命周期钩子时候,你怎么优化?
React 16 之后有三个生命周期被废除:
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
挂载阶段
-
constructor
如果不初始化 state 或不进⾏⽅法绑定,则不须要为 React 组件实现构造函数。
- 通过给 this.state 赋值对象来初始化外部 state。
- 为事件处理函数绑定实例
-
getDerivedStateFromProps
静态方法,当接管到新的
props
去更新state
时,能够应用getDerivedStateFromProps
-
render
纯函数,只返回须要渲染的货色,不应该蕴含其它的业务逻辑, 能够返回原生的 DOM、React 组件、Fragment、Portals、字符串和数字、Boolean 和 null 等内容
-
componentDidMount
组件挂载之后调用,能够操作 dom 与网络申请
更新阶段
- getDerivedStateFromProps 此办法在更新挂载阶段都可能会调用
- shouldComponentUpdate
shouldComponentUpdate(nextProps, nextState)
,有两个参数nextProps
和nextState
,示意新的属性和变动之后的state
,返回一个布尔值,true
示意会触发从新渲染,false
示意不会触发从新渲染,默认返回true
, 咱们通常利用此生命周期来优化 React 程序性能 - render: 更新阶段也会触发此生命周期
- getSnapshotBeforeUpdate
getSnapshotBeforeUpdate(prevProps, prevState)
,这个办法在render
之后,componentDidUpdate
之前调用,有两个参数prevProps
和prevState
,示意之前的属性和之前的state
,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate
,如果你不想要返回值,能够返回 null,此生命周期必须与componentDidUpdate
搭配应用 - componentDidUpdate
componentDidUpdate(prevProps, prevState, snapshot)
,该办法在getSnapshotBeforeUpdate
办法之后被调用,有三个参数prevProps
,prevState
,snapshot
,示意之前的 props,之前的 state,和 snapshot。第三个参数是getSnapshotBeforeUpdate
返回的, 如果触发某些回调函数时须要用到 DOM 元素的状态,则将比照或计算的过程迁徙至getSnapshotBeforeUpdate
,而后在componentDidUpdate
中对立触发回调或更新状态。
卸载阶段
- componentWillUnmount 当组件被卸载或者销毁了就会调用,咱们能够在这个函数里去革除一些定时器,勾销网络申请,清理有效的 DOM 元素等垃圾清理工作。
- UNSAFE_componentWillMount
UNSAFE_componentWillMount() 在挂载之前被调⽤;它在 render() 之前调⽤,因而在此⽅法中同步调⽤ setState() 不会⽣效;需要的话⽤ componentDidMount 代替。
- UNSAFE_componentWillReceiveProps
UNSAFE_componentWillReceiveProps() 会在已挂载的组件接管新的 props 之前被调⽤;如果你须要更新状态以响应 prop 更改(例如,重置它),你能够⽐较 this.props 和 nextProps 并在此 ⽅法中使⽤ this.setState() 执⾏ state 转换。
-
UNSAFE_componentWillUpdate
- 当组件收到新的 props 或 state 时,会在渲染之前调⽤ UNSAFE_componentWillUpdate();
- 使⽤此作为在更新发⽣之前执⾏筹备更新的机会;
- 初始渲染不会调⽤此⽅法;
事件处理
- this 绑定问题:在用户自定义的函数中没有 this。
- React 的数据流是单向的,没有数据绑定。
留神::
- React 事件的命名采纳小驼峰式(camelCase),而不是纯小写。且事件名称之后不能加 (),否则会间接执行
- 不能通过返回 false 的形式阻止默认行为。必须显式的应用 preventDefault
React 组件中的事件处理函数
- constructor 函数中 bind
class ReactEvent extends Component {constructor(props) {super(props);
// 强制绑定
this.handleClick = this.handleClick.bind(this);
}
handleClick() {console.log('Click');
}
render() {return <button onClick={this.handleClick}>Click Me</button>;
}
}
- 应用箭头函数
- render 中应用箭头函数
class ReactEvent extends Component {handleClick() {console.log('Click');
}
render() {return <button onClick={() => this.handleClick()}>Click Me</button>;
}
}
- 应用 class fields 语法
class ReactEvent extends Component {
// 此函数会被绑定到 ReactEvent 类的实例
handleClick = () => {console.log('Click');
}
render() {return <button onClick={this.handleClick}>Click Me</button>;
}
}
- 在 render 中应用 bind
class ReactEvent extends Component {handleClick() {console.log('Click');
}
render() {return <button onClick={this.handleClick.bind(this)}>Click Me</button>;
}
}
参考文章
- MVC、MVP 和 MVVM
- React 生命周期示意图
- React 生命周期