React学习之让组件和属性齐飞(三)

前端之家收集整理的这篇文章主要介绍了React学习之让组件和属性齐飞(三)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

何为组件?

组件就是让你可以独立于UI的控件了,从某种意义上来看,组件的开发有点像javascript函数式编程,也就是说组件像是个函数,输入一定的数据,然后处理完输出,将数据展现在视图中。

1.函数式组件(又称功能型组件)和类组件

标题大家就知道函数式组件是什么鬼了,也就是组件的开发,简单地说就是写一个函数,如下:

function We(props) {
  return <h1>Hello,{props.name}</h1>;
}

因为它遵循组件的特性,即输入一个props对象作为参数,然后有返回一个JSX对象,记住参数一定要为props,返回值一定是JSX对象哦,不然可不是函数式组件(稍微有点概念性的问题,尴尬)。

当然,重点戏到啦,那就是我们亲爱的ES6class,这个class来定义类和我们ES5中定义对象其实是一样,只是换了一个方式,让对象创建更加普遍和通俗化,(我想想,后续我再补ES6学习系列,简直happy happy)

class We extends React.Component {
  render() {
    return <h1>Hello,{this.props.name}</h1>;
  }
}

从一定的观点上看,函数式组件和类组件是等价的
接下来我将会用函数式组件来讲解,因为类组件写麻烦一些,但是通过上述的描叙,大家应该可以非常轻松的将函数式组件改装为类组件

2.视图展示组件内容

在我前两篇博客中,我们只知道用DOM元素标签来填充JSX语句,就是div,img,p,h等等,如下:

const e1 = <div />;
const e2 = <img />;
const e3 = <p />;

如今学了上面两种组件方式后,我们终于可以解放啦,我们可以用组件来填充JSX语句,用它来代替我们之前的DOM节点,简直满满的幸福:

const el = <We name="tm7" />;

那我们的React如何处理组件元素的呢?

React识别到了一个JSX元素为一个已经定义的组件JSX,它会通过JSX属性将对应的props对象传递给组件JSX,如下:

function We(props) {
  return <h1>Hello,{props.name}</h1>;
}
/** class We extends React.Component{ render(){ return <h1>hello,{this.props.name}</h1> } } **/
const el = <We name="tm7" />;
ReactDOM.render(
  el,document.getElementById('root')
);

上述代码做了如下几件事情:

  1. ReactDOM.render()函数识别出JSX为一个组件元素<We name="tm7" />
  2. React识别出组件元素中的props对象{name:"tm7"},将props对象传入组件元素
  3. 我们的组件元素调用响应的视图渲染函数进行处理,如果是类组件则是调用Render(),如果是函数式组件则是调用函数本身,而返回值为<h1>hello,tm7</h1>,其实返回的是一个JSX对象
  4. JSX会被处理为DOM节点,渲染在视图中

问题来啦,也就是说基本组件语法讲了,该注意的问题就需要提醒一下了

组件元素定义的JSX必须是大写字母开头,也就是说<we/>是错的,<We/>才是对的,虽然我没有看过源码,但是就官方网站上的说明来看,React识别是DOMJSX还是组件型JSX的区别就是开头字母有没有大写,如果大写了,就是组件,React就会去当前的作用域中寻找有没有相应的组件可以用。

3.构造复合组件

复合,就是融合多个组件,在一个组件中调用另外一些组件,获得那些组件的输出,然后再输出
实例如下:

function We(props) {
  return <h1>Hello,{props.name}</h1>;
}
function App() {
  return (
    <div>
      <We name="tm7" />
      <We name="jxy" />
      <We name="cxl" />
    </div>
  );
}
ReactDOM.render(
  <App />,document.getElementById('root')
);

知识题记

如果你想在一个已经存在的应用中增加别的组件的话,除了,前一篇文章说的:另选一个根节点可以重新处理(其实这种方式不算是增加到已有应用中)外,所谓的应用其实是一个大型JSX组件标签,而所谓的增加额外组件就是在这个JSX组件标签增加其它的组件,从而形成一个应用。

这里还要说的是,每一个<script>中都是一个独立的作用域

同时我们组件返回的一定是一个JSX元素语句,而不是两个,实例如下:

//true
return (<div>
    <h1>tm7</h1>
    <h1>jxy</h1>
</div>
);

//false
return (
    <h1>tm7</h1>
    <h1>jxy</h1>
);

4.尽可能提纯我们的代码

首先我们要有个观念,不是越多的组件越好,也不是组件啥都没有就好了,适当的提取一些JSX元素为一个组件元素会提高我们的代码的可读性和易用性。

实例如下:

function View(props) { return ( <div className="View"> <div className="UserInfo"> <img className="Avatar" src={props.author.avatarUrl} alt={props.author.name} /> <div className="UserInfo-name"> {props.author.name} </div> </div> <div className="View-text"> {props.text} </div> <div className="View-date"> {props.date} </div> </div> ); } ReactDOM.render( <View text="tm7" date="new Date()" author={{name:'aaa',avatarUrl:'bbb'}}/>,document.getElementById('example') );

我们可以适当的减少这一段代码,比如进行如下提取

function Avatar(props) {
  return (
    <img className="Avatar"
      src={props.user.avatarUrl}
      alt={props.user.name}
    />
  );
}

代码就变为了

function View(props) {
 return (
    <div className="View">
      <div className="UserInfo">
        <Avatar user={props.author} />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="View-text">
        {props.text}
      </div>
      <div className="View-date">
        {props.date}
      </div>
    </div>
  );
}

我们接着提取

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">
        {props.user.name}
      </div>
    </div>
  );
}

代码又简化了

function View(props) {
 return (
    <div className="View">
      <UserInfo user={props.author} />
      <div className="View-text">
        {props.text}
      </div>
      <div className="View-date">
        {props.date}
      </div>
    </div>
  );
}

提取行为的可用性和必要性

虽然提取过程是繁琐无聊的,但是当我们开发比较大的应用的时候,我们可能会重复大量相同的UI,那么提取元素对我们开发大型应用和维护应用有着很大的帮助,同时,即便不是大型应用,当我们写一些较为复杂的组件时,提取也是有必要的,我们要让我们的组件更具可读性和重塑性,同时重复UI必然存在,如此提取还是无法避免。

5.属性对象props和只读性Read-Only

不管你是声明的函数式组件还是类组件,只要一定义,属性便不能改变,只能读取,也就是说,当声明一个组件后,对象是无法扩展的,不能对它增加属性

实例如下:

var a = View({author:{name:'aaa',avatarUrl:'bbb'}});
a.tm = "tm7";

会报错:object is not extensible,表示无法扩展。

同时对于props的处理,由于props是一个对象,大家可以用javascript语法对他进行处理,即我们给JSX元素进行属性设置时,可以直接看成给props对象进行属性赋值。

同时这里涉及一个规范:javascript函数式编程,下面是一个标准的简单函数式编程:

function sum(a,b) {
  return a + b;
}

一般函数式编程评判的标准是,同一组输入,一定会产生同样的结果,不会对输入数据产生影响,这就是我们学数学知道的函数映射f(x),比如:二元一次方程,等等

如下则不是一个函数式编程

function wd(ac,am) {
  retac.to -= am;
}

它会影响输入的数据,产生的结果也是不可测的

总的来说,React是非常灵活的,但是也是很操蛋的,它有它的一套评判标准和严格的规范约束,官网上也提到过,所有的React组件都必须是一个纯的函数,即基于函数式编程的函数,一种输入只会对应一种结果,同时不会影响输入的数据

下一篇博客将说说前一篇博客说到的,每次用render函数进行覆盖,多难受啊,放心,React肯定给你解决方案啦,安啦,安啦

猜你在找的React相关文章