【React】基础

React

React 是?个声明式,?效且灵活的?于构建?户界?的 JavaScript 库。使? React 可以将? 些简短、独?的代码?段组合成复杂的 UI 界?,这些代码?段被称作“ 组件” 。
MVC与MVVM
  • MVC
【React】基础
文章图片

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。
这里主要讲的是前端的MVC实现,不要跟后端的MVC搞混了。它的目的是:
  1. 代码复用;
  2. 划分职责,方便后期维护;
Model(模型):负责保存应用数据,与后端数据进行同步
View(视图):负责视图展示,将model中的数据可视化
Controller(控制器):负责业务逻辑,根据用户行为对Model数据进行修改
【React】基础
文章图片

// 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
【React】基础
文章图片

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】基础
文章图片

由上图可知,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),有两个参数nextPropsnextState,表示新的属性和变化之后的state,返回一个布尔值,true表示会触发重新渲染,false表示不会触发重新渲染,默认返回true,我们通常利用此生命周期来优化React程序性能
  • render: 更新阶段也会触发此生命周期
  • getSnapshotBeforeUpdate getSnapshotBeforeUpdate(prevProps, prevState),这个方法在render之后,componentDidUpdate之前调用,有两个参数prevPropsprevState,表示之前的属性和之前的state,这个函数有一个返回值,会作为第三个参数传给componentDidUpdate,如果你不想要返回值,可以返回null,此生命周期必须与componentDidUpdate搭配使用
  • componentDidUpdate componentDidUpdate(prevProps, prevState, snapshot),该方法在getSnapshotBeforeUpdate方法之后被调用,有三个参数prevPropsprevStatesnapshot,表示之前的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();
    • 使?此作为在更新发?之前执?准备更新的机会;
    • 初始渲染不会调?此?法;
事件处理
  1. this绑定问题:在用户自定义的函数中没有this。
  2. React的数据流是单向的,没有数据绑定。
【【React】基础】注意::
  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。且事件名称之后不能加 (),否则会直接执行
  • 不能通过返回 false 的方式阻止默认行为。必须显式的使用 preventDefault
React组件中的事件处理函数
  1. constructor函数中bind
class ReactEvent extends Component { constructor(props) { super(props); //强制绑定 this.handleClick = this.handleClick.bind(this); } handleClick() { console.log('Click'); } render() { return ; } }

  1. 使用箭头函数
  • render中使用箭头函数
class ReactEvent extends Component { handleClick() { console.log('Click'); } render() { return ; } }

  • 使用class fields语法
class ReactEvent extends Component { //此函数会被绑定到ReactEvent类的实例 handleClick = () => { console.log('Click'); } render() { return ; } }

  • 在render中使用bind
class ReactEvent extends Component { handleClick() { console.log('Click'); } render() { return ; } }

参考文章
  • MVC、MVP和MVVM
  • React生命周期示意图
  • React生命周期

    推荐阅读