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 相关文章推荐
jQuery each()小议
Mar 18 Javascript
Js判断参数(String,Array,Object)是否为undefined或者值为空
Nov 04 Javascript
Extjs表单输入框异步校验的插件实现方法
Mar 20 Javascript
如何使用Bootstrap 按钮实例详解
Mar 29 Javascript
关于javascript sort()排序你可能忽略的一点理解
Jul 18 Javascript
基于js的变量提升和函数提升(详解)
Sep 17 Javascript
jQuery实现简单的回到顶部totop功能示例
Oct 16 jQuery
解决vue单页使用keep-alive页面返回不刷新的问题
Mar 13 Javascript
Vue组件中的data必须是一个function的原因浅析
Sep 03 Javascript
使用mpvue搭建一个初始小程序及项目配置方法
Dec 03 Javascript
使用layer弹窗,制作编辑User信息页面的方法
Sep 27 Javascript
JavaScript原型链详解
Nov 07 Javascript
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
数据库相关问题
2006/10/09 PHP
基于Linux调试工具strace与gdb的常用命令总结
2013/06/03 PHP
Yii分页用法实例详解
2014/12/04 PHP
ThinkPHP打开验证码页面显示乱码的解决方法
2014/12/18 PHP
thinkphp Apache配置重启Apache1 restart 出错解决办法
2017/02/15 PHP
Javascript实现动态菜单添加的实例代码
2013/07/05 Javascript
没有document.getElementByName方法
2013/08/19 Javascript
iframe的onreadystatechange事件在firefox下的使用
2014/04/16 Javascript
JavaScript基本语法讲解
2015/06/03 Javascript
第一次接触神奇的Bootstrap基础排版
2016/07/26 Javascript
详解js中Number()、parseInt()和parseFloat()的区别
2016/12/20 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
Vue.js 踩坑记之双向绑定
2018/05/03 Javascript
浅谈angularJS2中的界面跳转方法
2018/08/31 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
2019/02/10 Javascript
VUE接入腾讯验证码功能(滑块验证)备忘
2019/05/07 Javascript
微信小程序缓存过期时间的使用详情
2019/05/12 Javascript
js实现车辆管理系统
2020/08/26 Javascript
[06:45]DOTA2卡尔工作室 英雄介绍幻影长矛手篇
2013/07/12 DOTA
Python+Django搭建自己的blog网站
2018/03/13 Python
python实现寻找最长回文子序列的方法
2018/06/02 Python
python3 cvs将数据读取为字典的方法
2018/12/22 Python
python中列表的切片与修改知识点总结
2019/07/23 Python
对Pytorch神经网络初始化kaiming分布详解
2019/08/18 Python
python中删除某个元素的方法解析
2019/11/05 Python
python读取ini配置文件过程示范
2019/12/23 Python
tensorflow 2.1.0 安装与实战教程(CASIA FACE v5)
2020/06/30 Python
美国领先的个性化礼品商城:Personalization Mall
2019/07/27 全球购物
如何在C# winform中异步调用web services
2015/09/21 面试题
就业自荐书
2013/12/05 职场文书
养殖项目策划书范文
2014/01/13 职场文书
党员群众路线整改措施及今后努力方向
2014/10/28 职场文书
公司员工安全协议书
2014/11/21 职场文书
调任通知
2015/04/21 职场文书
高三英语教学反思
2016/03/03 职场文书
vue实现Toast组件轻提示
2022/04/10 Vue.js