献给 Angular1 小伙伴的 react 学习教程

本文从Angular1开发者的视角出发,对比分析Angular1与React的不同之处,特别是针对组件属性、事件及方法等方面进行深入探讨,并分享了作者的学习心得。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很幸运刚毕业到公司,领导就给我选择了前端开发这个行当,而接触的第一个框架就是Angular1,和大部分人一样,一本大漠老师的《使用AngularJS开发下一代WEB应用》带我入门,也照着写了一些代码,看书的时候也觉得大部分理解了,但是一到实际项目开发完全找不到北了,我想这也是很多人的写照。

就自己的体会,前端开发水平可以大概分为三个层次,每一个层次都是一个质的跨越,第一层是入门级的(从Angular1来看就是ng-controller党,这样更形象一点),诚然这种模式已经比当年有了极大进步,但是同样的,如今的前端复杂程度大增,这种进步只能算不拖后腿,第二层是进阶级的,组件化开发已经在心中打下烙印,这些人看到的不是页面,而是一颗组件树(说的好玄啊^ ^),对于一般的团队,我认为能达到这个水平就够用了,每个成员打好基本功,这个团队是很不错的了。第三层,是我想象的,我认为在他们眼中都是数据,没有UI,数据就是UI,通过精妙的架构体系控制着数据的流动,同时掌控着数据在每一个环节的变化。这里的角度更多是按一个偏产品的前端开发团队来分析的,自己的视野有限欢迎大家讨论。我认为如果达到了第二层就算是脱离贫困奔小康甚至过上小资生活,对于生活(工作)遇到的困难都能比较轻松的应对。我认为一个框架的熟练度达到类似第二层是很重要的,否则盲目的追新是很难达到质的提升,所以希望大家共勉不要盲从,至少要在团队中技术能hold住,再去想技能树更新,这才会事半功倍的。

回到原题,由于项目演进的原因下半年会由Angular1转为React,因此自己是从一个Angular1的开发视角来学习react,有人会问为啥要用视角来学习,为啥要对比,我自己也不知道这是不是一个好的方式,但我个人觉得用一个更熟悉的视角,新知识会记得更深刻,也许文中的一些对比有误,请大家指正,go~

开始

Angular1作为一门09年的颠覆性技术,为前端开发带来了一场革命,但由于那时候没有成熟的模块化方案,没有ES6标准的推动,导致这场革命不是那么彻底。确实Angular1不够组件化,但Angular1带给其他框架的影响是巨大的,react,Vue的出现没有达到Angular1当年的颠覆,react和Vue的核心技术也都有着Angular1的影子(或者说变了形态的影子),因此这篇教程就是带大家在react上找寻Angular1熟悉的味道。

对比哪些

当然是angular.directive和angular.component,这也是Angular1最能体现组件化特征的地方。一般来说一个组件会对外暴露属性事件方法

属性

  • angular

在angular1中属性有三种@,<,=,@表示不可修改的属性,最常见的id都会用@来表示,如果@对应的值会变化时,要加上{{}},

<my-comp text={{::someText}}></my-comp>复制代码

修饰符<的样子就体现了单向数据流的特征,它类似Vue中watch的形式,在$onChanges中可以watch到属性的变化,不用再自己一个一个添加$watch*之类的东东了,

=这个样子也非常形象,父作用域和隔离作用域的属性都指向同一个地址空间,因此隔离作用域也可以修改父作用域的属性,这往往使得问题难以定位。

  • react

react的属性很js,没有angular那么多修饰符或者继承、隔离这些东西,react很开放,它告诉你属性应该像@一样是不可变的,但是它就是一个js对象,你可以改变它,但是你要自己承担所可能带来的后果,那么想想@改怎么写,react的props就该怎么用,想象一下我们在写一个指令叫MyProps,它目前只有一个{id:'@', width: '@'}

angular版

angular.directive('myProps', function(){
    return {
        restrict: 'E',
        scope: {
            id:'@',
            width: '@'
        },
        controller:function($scope){
            scope.width = scope.width || 200
        },
        template: `<button id='{{::id}}' width='{{::width}}'></button>`
    }
})复制代码

react版

class MyProps extends React.Component {
  render() {
    return (
      <button id={this.props.id} style={{ width: this.props.width + 'px' }}>
        idButton
        </button>
    )
  }
}
MyProps.defaultProps = { width: 200 }复制代码

react很js很class吧,其实思路是不是很相似,this.props就和scope一样,只不过react通过jsx实现了表达式计算。

事件

  • angular

在angular里事件一般用&来修饰,如果你希望对响应参数做定制也可以使用=

angular版

angular.directive('myProps', function(){
    return {
        restrict: 'E',
        scope: {
            id:'@',
            width: '@',
            click: '&'
        },
        controller:function($scope){
            scope.width = scope.width || 200
        },
        template: `<button id='{{::id}}' width='{{::width}}' ng-click='click()'></button>`
    }
})复制代码

react版

class MyButton extends React.Component {
  render() {
    return (
      <div>
        <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }} onClick={this.props.click}>clickMe</div>
      </div>
    )
  }
}

class MyEvent extends React.Component {
  constructor(props) {
    super(props)
  }
  clickHandler() {
    console.log('My Button Clicked')
  }
  render() {
    return (
      <MyButton id="event" click={this.clickHandler.bind(this)} w="200" h="40" bgColor="green" />
    )
  }
}

ReactDOM.render(
  <MyEvent />, document.getElementById('root'))复制代码

你也可以对响应参数做定制,就像angular中把事件修饰&变为=那样,这里就不上angular的了

react版本

class MyButton extends React.Component {
  constructor(props) {
    super(props)
  }
  clickHandler() {
    this.props.click(this.props.bgColor)
  }
  render() {
    return (
      <div>
        <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }} onClick={this.clickHandler.bind(this)}>clickMe</div>
      </div>
    )
  }
}

class MyEvent extends React.Component {
  constructor(props) {
    super(props)
  }
  clickHandler(color) {
    console.log('My Button color: ' + color)
  }
  render() {
    return (
      <MyButton id="event" click={this.clickHandler.bind(this)} w="200" h="40" bgColor="green" />
    )
  }
}

ReactDOM.render(
  <MyEvent />, document.getElementById('root'))复制代码

方法

其实方法并不是angular所包含的一个概念,angular提倡数据状态影响UI的理念,除了angular提供的一些ng-内置指令,我们要写一大堆双向绑定属性(伴随着一大堆$watch),性能堪忧,更重要的是你会发现定位问题很难(脏数据校验)。因此在我们项目除了disable、display之类会使用<,界面变更都采用方法,将指令的UI变更方法绑定到$scope.$parent上,这样父指令就可以通过这些方法来操作子指令的UI变更了。

angular版

angular.module('myApp',[]);  
myApp.controller('listCtrl',function($scope){    var display = false
   $scope.showOrHide=function(){  
      $scope.btn.setDisplay(display?'block':'none')
     display =!display
   };  
});  

myApp.directive('kid',function(){  
    return {  
        'restrict':'E',  
        scope:{id: '@'},
        template:'<div><button>click</button></div>',
        link: function(scope, elem) {
        scope.$parent[scope.id] = {
           setDisplay: function(display){
             elem.css('display', display)
           }
         }
      }
    }  
});复制代码

按照这个思路我们在react上也试试。

class MyButton extends React.Component {
  constructor(props) {
    super(props)
  }
  setDisplay(display) {
    this.refs.myButton_ref.style.display = display
  }
  render() {
    return (
      <div ref="myButton_ref">
        <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }}>clickMe</div>
      </div>
    )
  }
}

class MyEvent extends React.Component {
  constructor(props) {
    super(props)
    this.display = false
  }
  showOrHide() {
    this.child.setDisplay(this.display ? 'block' : 'none')
    this.display = !this.display
  }
  render() {
    return (
      <div>
        <MyButton id="event" w="200" h="40" bgColor="green" ref={(instance) => { this.child = instance }} />
        <button onClick={this.showOrHide.bind(this)}>showOrHide</button>
      </div>
    )
  }
}复制代码

代码中ref="myButton_ref"非常别扭,因为直接对dom的操作让我们感觉回到了jquery时代,因此这里我们应该使用一直未提到的state,那state像angular的什么呢,和指令中的controller很像,你可以在controller里对$scope里增加新的属性(这里也包含了父指令传进来的属性),因此angular里的$scope包含了react中的props和state,react把它分开会让使用者更加清楚,让使用者知道props是不能变的,state才是可变的。因此我们把代码中的MyButton稍作修改。

class MyButton extends React.Component {
  constructor(props) {
    super(props)
    this.state = { display: 'block' } // 初始值
  }
  setDisplay(display) {
    this.setState({ display })
  }
  render() {
    return (
      <div style={{ display: this.state.display }}>
        <div id={this.props.id + '_btn'} style={{ width: this.props.w + 'px', height: this.props.h + 'px', backgroundColor: this.props.bgColor }}>clickMe</div>
      </div>
    )
  }
}复制代码

最后

这篇教程主要从自己这个Angular1使用者的的视角来看react,我觉得对于Angular开发人员来说是一个不错的学习react的思路,本人也是刚刚接触react,文中如有错误也请及时指正。下一篇将对Angular1指令的生命周期和react组件生命周期做以对比,谢谢大家。

转载于:https://juejin.im/post/5903eaf0a22b9d0065d5283f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值