React如何创建组件


Posted in Javascript onJune 27, 2021

前言

这节我们将介绍 React 中组件的类别,以及如何创建和使用组件。

本文会向你介绍以下内容:

  • 创建类组件
  • 创建函数组件
  • 渲染组件
  • 合成组件
  • 提取组件
  • Props 是只读的

组件介绍

组件(Components) 让你可以将用户界面分成独立的,可复用的小部件,并可以对每个部件进行单独的设计。

从定义上来说, 组件就像JavaScript的函数。组件可以接收任意输入(称为”props”), 并返回 React 元素,用以描述屏幕显示内容。

Props , 即属性(Property), 在代码中写作 props,故可用 props 指代 properties。
react中有两种组件:类组件(class components)、函数组件(function components)

创建类组件

类组件的定义有如下要求:

  • 类组件需要继承自 React.Component
  • 类组件必须实现render函数

在ES6之前,可以通过create-react-class 模块来定义类组件,但是目前官网建议我们使用ES6的class类定义。

使用class定义一个组件:

class App extends Component {
  constructor() {
    super()
    this.state = {}
  }

  render() {
    return <h2>Hello App</h2>
  }
}

我们来详细分析一下类组件有哪几个部分

  • constructor:这是类组件的构造函数,是可选的,我们通常在constructor中初始化一些数据;
  • this.state:我们在constructor中给类组件加入state属性,你可以理解为组件中有一个state对象,其中包含着各种属性,用于维护组件内部的数据。同时你可以通过this.state.<属性名>访问该属性;
  • render(): 该方法是 class 组件中唯一必须实现的方法,类组件通过render()返回组件的显示内容;

关于 state

我们可以通过this.state给类组件添加数据对象,我们可以通过this.state.<属性名>去访问我们setState中的属性。

constructor(props) {
    super(props);
    this.state = {
      name:"xhs-rookies"
    }
  }

render(){
    return <h2>{this.state.name}</h2>
  }

但是我们想要修改上述例子中的name属性的时候,则必须通过react给我们规定好的setState()方法,去给state添加或者修改其中的数值。

this.state.name = 'new xhs-rookies' //错误的方式,不允许采用
this.setState({ name: 'new xhs-rookies' }) //正确的方式

简单点来说,在 react 中页面是通过数据进行渲染,使用setState()更新的数据,react 会帮我们执行render()去更新页面,从而将页面中用到 state 中的数据全部更新。

关于 render

当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回很多类型,很多时候我们选择让该方法返回 React 元素,然后交由 React 去渲染展示:

React 元素:

  • 通常通过 JSX 创建。
  • 例如,<div/> 会被 React 渲染为 DOM 节点,<MyComponent/> 会被 React 渲染为自定义组件;
  • 无论是 <div/> 还是 <MyComponent/> 均为 React 元素。

详细关于 render() 方法的内容请见React.Component - Render)

创建函数组件

函数组件是使用 function 来进行定义的函数,只是这个函数会返回和类组件中 render 函数返回一样的内容。

跟类组件相比,函数组件有自己的特点:

  • 没有生命周期,也会被更新并挂载,但是没有生命周期函数;
  • 没有 this(组件实例);
  • 没有内部状态(state);

我们来定义一个函数组件:

export default function App() {
  return <div>xhs rookies</div>
}

渲染组件

在前几篇中, 我们只遇到代表 DOM 标签的 React 元素:

const element = <div />

然而,元素也可以代表用户定义的组件:

const element = <Welcome name="xhs rookies" />

当 React 遇到一个代表用户定义组件的元素时,它将 JSX 属性以一个单独对象的形式传递给相应的组件。 我们将其称为 “props” 对象。

比如, 以下代码在页面上渲染“xhs rookies”:

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

const element = <Welcome name="xhs rookies" />
ReactDOM.render(element, document.getElementById('root'))

我们简单解释一下上面这个例子:

  • 我们调用了 ReactDOM.render() 方法并向其中传入了 <Welcome name="xhs rookies" /> 元素。
  • React 调用 Welcome 组件,并向其中传入了 {name: 'xhs rookies'} 作为 props 对象。
  • Welcome 组件返回 <h1>xhs rookies</h1>。
  • React DOM 迅速更新 DOM ,使其显示为 <h1>xhs rookies</h1>。

注意: 组件名称总是以大写字母开始。

举例来说, <div/> 代表一个 DOM 标签,而 <Welcome/> 则代表一个组件,并且需要在作用域中有一个 Welcome 组件。

你可以深入 JSX阅读更多关于这点背后的原因。

合成组件

组件可以在它们的输出中引用其它组件。这使得我们可以使用同样的组件来抽象到任意层级。一个按钮,一个表单,一个对话框,一个屏幕:在 React 应用中,所有这些都通常描述为组件。

例如,我们可以创建一个 App 组件,并在其内部多次渲染 Welcome:

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

function App() {
  return (
    <div>
      <Welcome name="rookie-Sara" />
      <Welcome name="rookie-Cahal" />
      <Welcome name="rookie-Edite" />
    </div>
  )
}

 
ReactDOM.render(<App />, document.getElementById('root'))

通常,新的 React apps 都有一个单独的顶层 App 组件。然而,如果你在已有的应用中整合 React,你可以需要由下至上地, 从类似于 Button 这样的小组件开始, 逐渐整合到视图层的顶层。

提取组件

不要害怕把一个组件分为多个更小的组件。

举个例子,思考下名 Comment 组件:

function Comment(props) {
  return (
    <div className="Comment">
      <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="Comment-text">{props.text}</div>
      <div className="Comment-date">{formatDate(props.date)}</div>
    </div>
  )
}

它接受 author(一个对象),text(一个字符串)和 date(一个日期)作为 props。

这个组件修改起来很麻烦,因为它是被嵌套的,而且很难复用其中的某个部分。让我们从其中提取一些组件。

首先,提取头像 Avatar:

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

Avatar 组件不用关心它在 Comment 中是如何渲染的。这是为什么我们它的 prop 一个更通用的属性名: user, 而不是 author 的原因。

我们建议从组件本身的角度来命名 props 而不是它被使用的上下文环境。

我们可以稍微简化一下 Comment 组件:

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

接下来,我们提取用户信息 UserInfo 组件, 用于将 Avatar 显示在用户名旁边:

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

这使我们可以进一步简化 Comment 组件:

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

提取组件可能看起来是一个繁琐的工作,但是在大型的 Apps 中可以回报给我们的是大量的可复用组件。一个好的经验准则是如果你 UI 的一部分需要用多次 (Button,Panel,Avatar),或者本身足够复杂(App,FeedStory,Comment),最好的做法是使其成为可复用组件。

Props 是只读的

无论你用函数或类的方法来声明组件, 它都无法修改其自身 props. 思考下列 sum (求和)函数:

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

这种函数称为 “纯函数” ,因为它们不会试图改变它们的输入,并且对于同样的输入,始终可以得到相同的结果。

反之, 以下是非纯函数, 因为它改变了自身的输入值:

function withdraw(account, amount) {
  account.total -= amount
}

虽然 React 很灵活,但是它有一条严格的规则:

注意: 所有 React 组件都必须是纯函数,并禁止修改其自身 props 。
当然, 应用 UI 总是动态的,并且随时有可以改变。

如果我们想要动态改变 UI,那么就会涉及到我们上面说到的state(状态) 。我们通过动态的改变state来渲染整个页面,我们后面会提及,详情见 深入理解 setState

到此这篇关于React如何创建组件的文章就介绍到这了,更多相关React 创建组件内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
Javascript实现页面跳转的几种方式分享
Oct 26 Javascript
手机端网页点击链接触发自动拨打或保存电话的示例代码
Aug 15 Javascript
javascript实现简单的贪吃蛇游戏
Mar 31 Javascript
基于jquery实现的仿优酷图片轮播特效代码
Jan 13 Javascript
Node.js实现JS文件合并小工具
Feb 02 Javascript
Javascript的表单验证长度
Mar 16 Javascript
基于JavaScript实现点击页面任何位置返回
Aug 31 Javascript
Angular2 Service实现简单音乐播放器服务
Feb 24 Javascript
AngularJS 前台分页实现的示例代码
Jun 07 Javascript
Vue Prop属性功能与用法实例详解
Feb 23 Javascript
我所理解的JavaScript中的this指向
Sep 04 Javascript
vue如何使用rem适配
Feb 06 Vue.js
Vue3.0写自定义指令的简单步骤记录
关于JavaScript回调函数的深入理解
Jun 27 #Javascript
vue.js Router中嵌套路由的实用示例
Jun 27 #Vue.js
vite+vue3.0+ts+element-plus快速搭建项目的实现
vue-router中hash模式与history模式的区别
Vue-Element-Admin集成自己的接口实现登录跳转
浅谈Web Storage API的使用
You might like
PHP4 与 MySQL 交互使用
2006/10/09 PHP
PHP file_exists问题杂谈
2012/05/07 PHP
PHP date()函数警告: It is not safe to rely on the system解决方法
2014/08/20 PHP
PHP分页类集锦
2014/11/18 PHP
PHP编程开发怎么提高编程效率 提高PHP编程技术
2015/11/09 PHP
PHP中如何防止外部恶意提交调用ajax接口
2016/04/11 PHP
PHP实现活动人选抽奖功能
2017/04/19 PHP
php中try catch捕获异常实例详解
2020/08/06 PHP
javascript 可以拖动的DIV(二)
2009/06/26 Javascript
让人印象深刻的10个jQuery手风琴效果应用
2012/05/08 Javascript
jquery设置text的值示例(设置文本框 DIV 表单值)
2014/01/06 Javascript
js从Cookies里面取值的简单实现
2014/06/30 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
jquery 点击元素后,滚动条滚动至该元素位置的方法
2016/08/05 Javascript
Jquery AJAX POST与GET之间的区别详细介绍
2016/10/17 Javascript
prototype与__proto__区别详细介绍
2017/01/09 Javascript
微信小程序 利用css实现遮罩效果实例详解
2017/01/21 Javascript
用js将long型数据转换成date型或datetime型的实例
2017/07/03 Javascript
Node.js npm命令运行node.js脚本的方法
2018/10/10 Javascript
vue 组件内获取actions的response方式
2019/11/08 Javascript
Python实现根据指定端口探测服务器/模块部署的方法
2014/08/25 Python
python将文本中的空格替换为换行的方法
2018/03/19 Python
Scrapy框架爬取Boss直聘网Python职位信息的源码
2019/02/22 Python
Django 过滤器汇总及自定义过滤器使用详解
2019/07/19 Python
python判断自身是否正在运行的方法
2019/08/08 Python
python 利用toapi库自动生成api
2020/10/19 Python
HTML5之WebGL 3D概述(下)—借助类库开发及框架介绍
2013/01/31 HTML / CSS
运动鞋、街头服装、手表和手袋的实时市场:StockX
2020/11/25 全球购物
环境工程毕业生自荐信
2013/11/17 职场文书
高中生学习的自我评价
2013/12/14 职场文书
小学生元旦感言
2014/02/26 职场文书
公共场所禁烟倡议书
2014/08/30 职场文书
汽车服务工程专业自荐信
2014/09/02 职场文书
群众路线教育实践活动自我剖析思想汇报
2014/10/04 职场文书
大学生自我推荐信范文
2015/03/24 职场文书
2015公务员年度考核评语
2015/03/25 职场文书