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 相关文章推荐
js动画(animate)简单引擎代码示例
Dec 04 Javascript
利用js判断浏览器类型(是否为IE,Firefox,Opera浏览器)
Nov 22 Javascript
Js判断CSS文件加载完毕的具体实现
Jan 17 Javascript
button没写type=button会导致点击时提交
Mar 06 Javascript
全面解析JavaScript中apply和call以及bind(推荐)
Jun 15 Javascript
jQuery中slidedown与slideup方法用法示例
Sep 16 Javascript
微信小程序开发经验总结(推荐)
Jan 11 Javascript
详解vue.js的devtools安装
May 26 Javascript
JavaScript模拟文件拖选框样式v1.0的实例
Aug 04 Javascript
vue中动态添加class类名的方法
Sep 05 Javascript
通过JQuery,JQueryUI和Jsplumb实现拖拽模块
Jun 18 jQuery
详细聊聊浏览器是如何看闭包的
Nov 11 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
使用YUI+Ant 实现JS CSS压缩
2014/09/02 PHP
PHP简单判断字符串是否包含另一个字符串的方法
2016/03/25 PHP
phpinfo无法显示的原因及解决办法
2019/02/15 PHP
PHP从零开始打造自己的MVC框架之路由类实现方法分析
2019/06/03 PHP
Laravel 错误提示本地化的实现
2019/10/22 PHP
javascript的函数
2007/01/31 Javascript
不要小看注释掉的JS 引起的安全问题
2008/12/27 Javascript
javascript实现的距离现在多长时间后的一个格式化的日期
2009/10/29 Javascript
jQuery(非HTML5)可编辑表格实现代码
2012/12/11 Javascript
使用js实现一个可编辑的select下拉列表
2014/02/20 Javascript
js简单工厂模式用法实例
2015/06/30 Javascript
javascript cookie的简单应用
2016/02/24 Javascript
JavaScript Date对象详解
2016/03/01 Javascript
基于JS实现密码框(password)中显示文字提示功能代码
2016/05/27 Javascript
Angularjs中$http以post请求通过消息体传递参数的实现方法
2016/08/05 Javascript
js enter键激发事件实例代码
2016/08/17 Javascript
JS 拼凑字符串的简单实例
2016/09/02 Javascript
微信小程序实战之运维小项目
2017/01/17 Javascript
jquery.uploadifive插件怎么解决上传限制图片或文件大小问题
2017/05/08 jQuery
electron + vue项目实现打印小票功能及实现代码
2018/11/25 Javascript
layui radio点击事件实现input显示和隐藏的例子
2019/09/02 Javascript
[51:53]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第二场 11.01
2020/11/02 DOTA
python各种语言间时间的转化实现代码
2016/03/23 Python
Python单元测试实例详解
2018/05/25 Python
简单谈谈python基本数据类型
2018/09/26 Python
python使用递归的方式建立二叉树
2019/07/03 Python
简单了解Django ContentType内置组件
2019/07/23 Python
pycharm运行scrapy过程图解
2019/11/22 Python
python中栈的原理及实现方法示例
2019/11/27 Python
新百伦折扣店:Joe’s New Balance Outlet
2016/08/20 全球购物
英国二手iPhone、音乐、电影和游戏商店:musicMagpie
2018/10/26 全球购物
介绍一下Ruby中的对象,属性和方法
2012/07/11 面试题
奖学金自我鉴定范文
2013/10/03 职场文书
银行学习十八大感想
2014/01/11 职场文书
创文明城市标语
2014/06/16 职场文书
《秋天的雨》教学反思
2016/02/19 职场文书