手把手学习React - 组件与自定义属性

1,707 阅读7分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第27天,点击查看活动详情

前言

大家好,从上篇文章React 元素渲染开始我们进行了React相关知识的学习,那么关于react学习也是一些简单的入门教程。上篇文章我们学习了React元素的概念以及如何渲染一个react元素,在上篇文章的最后我们还将React元素和js代码进行了分离以实现代码复用的目的,其实已经涉及到了我们接下来要分享的知识,也就是组件,下面我们就来看下什么是组件,如何定义和使用组件

React组件的定义及分类

什么是组件?其实组件类似于JavaScript中的函数,它接收任意的输入参数(props),并返回用于描述页面展示内容的React元素,也就是说我们在javascript函数中写一些react元素,处理一些逻辑,其实这就是一个组件。 组件可以将UI拆分成一个个独立的可复用的代码片段,并且可以对每个片段进行独立构思和管理,因此组件还能够很好的实现代码的复用。

React 组件可以分为两种形式:类(class)组件和函数(function)组件,下面我们先来看下函数组件。

函数式组件

函数式组件其实就是写一个JavaScript函数,接收一个props对象作为参数,并返回用于描述页面内容的React元素(JSX语法),这就构成了一个函数式组件。 但需要注意的是:组件名称必须以大写字母开头,因为React会将以小写字母开头的组件视为原生 DOM 标签。例如,< div /> 代表 HTML 的 div 标签,而 < Clock /> 则代表一个组件,并且需在作用域内使用 Clock。

函数式组件属于静态组件,因此函数组件在渲染后其内容是不会改版的,除非通过React.render重新渲染或者通过React HOOKS来改变(关于react hooks后面会有专门的文章分享)

下面我们以一个时钟组件为例编写一个函数式组件

function Clock(props){
   return <div>{new Date().toLocaleString()}</div>	
}

如上代码看上去跟JavaScript函数没啥区别,唯一不同的就是可以在js函数中写一些div标签等,其实这就是一个函数组件,函数里面的div标签等就是react元素(jsx语法)。说完了函数组件我们再来看下类组件。

类组件

  • 上面我们已经说过,定义一个React组件可以有两种方式,除了定义函数组件外,我们还可以使用ES6中的类(class)来定义React组件
  • 类组件顾名思义:就是通过声明一个类来实现定义一个React组件;定义类组件有如下几个特点:
    • 1.定义类组件必须要继承自React的Component类或React.PureComponent
    • 2.类中必须要定义一个名为render的函数,函数的返回值应该是React元素(JSX语法)
    • 3.在类的内部默认会有个props属性(继承自Component)可以直接使用
    • 4.与函数组件一样,组件名称必须以大写字母开头
    • 5.在类的构造函数(constructor)中通过this.props访问属性值是获取不到的,因为这时props还没有挂载到this.props上,要等constructor执行完成之后才会挂载
    • 6.如果非要在构造函数(constructor)中使用this.props来获取,则可以把外面传进来的props传递给constructor中的父类构造函数super从而实现this.props的挂载
    • 7.类组件是动态组件,基于数据驱动视图渲染

下面我们还是以时钟组件为例:编写一个类组件

class Clock extends React.Component{
    render(){
       return <div>{new Date().toLocaleString()}</div>  	
   }	
}

组件的渲染

  • 前面我们接触到的React元素都只是DOM标签,比如div、h1、span等等。那么我们自己定义的组件该如何渲染呢?
  • 其实不管是函数组件还是类组件,渲染方式跟React元素是一样的,也是把函数名或类名当做普通标签直接使用即可
  • 组件跟普通DOM标签一样,既可以是单闭合也可以是双闭合,如果标签内需要显示文本或者是其它子元素,这时就需要用双闭合标签包起来
  • 在使用过程中,我们也可以给组件传递各种属性,这些属性(attributes)以及组件内部的子组件(children)会被转换为单个对象传递个组件,这个对象被称为“props”,就是在函数组件或类组件定义时我们提到的那个props
  • ReactDOM在将组件转换为虚拟DOM时(转换为React.createElement(xxx)),会进行判断,如果生成的虚拟DOM对象的type是一个函数或者类(也就是说渲染的是一个函数组件或类组件),则首先会把函数执行并把解析出来的props传递给函数,如果是一个类,则会创建类的实例并把解析出来的props传递给这个类
  • 然后在函数组件或类组件的内部我们就可以直接通过props.xxx或this.props.xxx来获取和使用组件渲染时传递过来的属性
  • 传递进来的属性是只读的(只能获取不能修改里面的值),如果想要修改可以通过一个中间变量(状态state)来进行操作
function Welcome(props){
   return <h1>Hello, {props.name}</h1>
}
ReactDOM.render(
   <Welcome name="Alvin" />,//单闭合标签
   document.getElementById("root")
);

上述代码运行结果,会在页面上显示 “Hello, Alvin”,Alvin就是我们通过name属性动态传递给Welcome组件的

组合组件

在日常项目开发中,我们自定义的组件中也可直接引入其它自定义组件作为子元素,这样我们就可以把不同的功能模块封装成不同的独立的组件,比如按钮、表单、对话框等等,以方便管理和代码的松耦合,然后再通过其它组件来使用,这样就形成了组合组件。 例如,我们可以创建一个包含多个组件的App组件,在这个App组件中可以包含多次渲染的同一个Welcome组件,也可以是另外的Clock组件,还可以是原生的DOM元素标签。

function Clock(props){
    return <div>{new Date().toLocaleString()}</div>	
}
function Welcome(props){
    return <h1 style={{color:'red'}}>Hello, {props.name}</h1>;
}
function App(props){
    return <div>
            <Clock />	
            <Welcom name="Alvin" />
            <Welcom name="Yinnes" />
            <Welcom name="Yaolu" />
        </div>
}
ReactDOM.render(
    <App />,
    document.getElementById('root')
);

Props

  • 上面在讲组件定义时,我们已经提到过props属性。当我们在渲染使用组件时无论是函数组件还是类组件,只要给标签元素添加了属性,那么这些属性都会被转换为props对象传递给函数或者类。
  • 如果在渲染组件时使用的是双闭合标签,并且在标签内部又嵌套了其它组件或添加了文本内容,则这些子组件或文本内容同样会被转换成普通对象或者是字符串并放置在props下的children属性中
  • 在组件中如果想获取传递的属性值或者子组件内容则可以直接通过props.属性名或props.children.xxx获取
function Welcome(props){
   //通过props.name获取传递的属性值
   return <h1>Hello, {props.name}</h1>
}
ReactDOM.render(
   <Welcome name="Alvin" />,//单闭合标签,传递了name属性
   document.getElementById("root")
);

总结

本次分享我们学习了React中组件的概念、组件的分类以及组件的使用。简单总结如下:

在React中组件分为类组件和函数组件,组件在渲染使用时跟普通dom标签一样,我们可以像写html标签一样将react元素直接写在组件中,我们还可以把不同功能模块封装成不同的独立的组件,然后再在同一个组件中渲染使用,这样就形成了组合组件。如果想要给组件传值可以通过props属性的方式进行传递。

好了本次分享就到这里了。