React组件

1.组件基本介绍

  • 组件是React中最基本的内容,使用React就是在使用组件
  • 组件表示页面中的部分功能
  • 多个组件可以实现完整的页面功能
  • 组件特点:可复用,独立,可组合
    在这里插入图片描述

2.React创建组件的两种方式

2.1 函数组件

函数组件:使用JS的函数或者箭头函数创建的组件

  • 为了区分普通标签,函数组件的名称必须大写字母开头
  • 函数组件必须有返回值,表示该组件的结构
  • 如果返回值为null,表示不渲染任何内容

使用函数创建组件

function Hello () {
    return (
    	<div>这是我的函数组件</div>
    )
}

使用箭头函数创建组件

const Hello = () => <div>这是一个函数组件</div>

使用组件

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

例子:
01-函数组件-基本使用

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  1. 通过函数创建一个组件即可
    1. 组件的名字必须是大写开头  为了区分html原有的标签
    2. 组件必须返回一段结构
    3. 如果组件不想渲染任何的内容  也需要return null
*/
function Hello() {
  return <div>我是hello组件</div>
}

const element = (
  <div>
    <h1>函数组件</h1>
    {/* 使用组件 */}
    <Hello></Hello>
    <Hello></Hello>
  </div>
)

ReactDOM.render(element, document.getElementById('root'))

02-函数组件-箭头函数

import React from 'react'
import ReactDOM from 'react-dom'

const Hello = () =><div>我是Hello组件</div>
const element = (
  <div>
    <h1>函数组件</h1>
    {/* 使用组件 */}
    <Hello></Hello>
    <Hello></Hello>
  </div>
)

ReactDOM.render(element, document.getElementById('root'))

在这里插入图片描述

2.2 类与继承

2.2.1 class 基本语法

  • 在 ES6 之前通过构造函数创建对象
  • 在 ES6 中新增了一个关键字 class,类 和构造函数类似,用于创建对象
    -类与对象的区别
    -类:指的是一类的事物,是个概念,比如车 手机 水杯等
    -对象:一个具体的事物,有具体的特征和行为,比如一个手机,我的手机等, 类可以创建出来对象。
  • 类创建对象的基本语法
    -基本语法class 类名{}
    -构造函数constructor的用法,创建对象
    -在类中提供方法,直接提供即可
    -在类中不需要使用,分隔
/* class 类  extends 继承 */
// function Teacher(name, age) {
//   this.name = name
//   this.age = age
// }

// Teacher.prototype.sayHi = function () {
//   console.log('大家好,我是' + this.name)
// }

// const stu = new Teacher('松哥', 29)
// console.log(stu)
// stu.sayHi()

// class是一个语法糖
class Teacher {
  // 构造函数
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  sayHi() {
    console.log('大家好,我是' + this.name)
  }

  sing() {
    console.log('能够唱歌')
  }
}

const stu = new Teacher('松哥', 29)
console.log(stu)
stu.sing()

在这里插入图片描述

2.2.2 extends 实现继承

  • extends 基本使用
  • 类可以使用它继承的类中所有的成员(属性和方法)
  • 类中可以提供自己的属性和方法
  • 注意:如果想要给类中新增属性,必须先调用 super 方法
/* 
  Person  人

  Chinese 中国人
  African 非洲人
*/
class Person {
  constructor(name, gender) {
    this.name = name
    this.gender = gender
  }

  eat() {
    console.log('都会吃')
  }
}

class Chinese extends Person {
  constructor(name, gender) {
    // 父类的构造函数
    super(name, gender)
    this.skin = 'yellow'
  }
  pingpong() {
    console.log('打乒乓球')
  }
}

const c1 = new Chinese('姚明', 40)
console.log(c1)
c1.eat()
c1.pingpong()

class African extends Person {
  constructor(name, gender) {
    super(name, gender)
    this.skin = 'black'
  }
  run() {
    console.log('跑的贼快')
  }
}

const xh = new African('小黑', 30)
console.log(xh)

在这里插入图片描述

2.3 将组件提取到单独的js文件中

项目中的组件多了之后,该如何组织这些组件呢?

  • 选择一:将所有组件放在同一个JS文件中
  • 选择二:将每个组件放到单独的JS文件中
  • 组件作为一个独立的个体,一般都会放到一个单独的 JS 文件中

实现方式

  1. 创建Hello.js

  2. 创建组件(函数 或 类)

  3. 在 Hello.js 中导出该组件

  4. 在 index.js 中导入 Hello 组件

  5. 渲染组件,

05-类组件的语法

import { Component } from 'react'
import ReactDOM from 'react-dom'

/* 
  1. 类组件必须继承React.Component
  2. 必须提供render方法
  3. render方法必须由返回值,需要返回一段结构
*/
class Hello extends Component {
  render() {
    return <div>我是hello组件</div>
  }
}

const element = (
  <div>
    <h1>类组件</h1>
    <Hello></Hello>
    <Hello></Hello>
  </div>
)

ReactDOM.render(element, document.getElementById('root'))

在这里插入图片描述
06-把组件抽取到独立的js中
在这里插入图片描述

Demo

const Demo = () => <div>我是一个函数组件</div>
export default Demo

Hello

import { Component } from 'react'

class Hello extends Component {
  render() {
    return <div>我是一个Hello组件</div>
  }
}
export default Hello

index

import ReactDOM from 'react-dom'
import Hello from './components/Hello.jsx'
import Demo from './components/Demo.jsx'

const element = (
  <div>
    <h1>类组件</h1>
    <Hello></Hello>
    <Demo></Demo>
  </div>
)

ReactDOM.render(element, document.getElementById('root'))

在这里插入图片描述

2.4 有状态组件和无状态组件

  • 函数组件又叫做无状态组件 函数组件是不能自己提供数据【前提:基于hooks之前说的】
  • 类组件又叫做有状态组件 类组件可以自己提供数据,,,,组件内部的状态(数据如果发生了改变,内容会自动的更新)数据驱动视图
  • 状态(state)即组件的私有数据,当组件的状态发生了改变,页面结构也就发生了改变。
  • 函数组件是没有状态的,只负责页面的展示(静态,不会发生变化)性能比较高
  • 类组件有自己的状态,负责更新UI,只要类组件的数据发生了改变,UI就会发生更新。
  • 在复杂的项目中,一般都是由函数组件和类组件共同配合来完成的。【增加了使用者的负担,所以后来有了hooks

比如计数器案例,点击按钮让数值+1, 0和1就是不同时刻的状态,当状态从0变成1之后,UI也要跟着发生变化。React想要实现这种功能,就需要使用有状态组件来完成。
在这里插入图片描述

2.5 类组件的状态

  • 状态state即数据,是组件内部的私有数据,只有在组件内部可以使用
  • state的值是一个对象,表示一个组件中可以有多个数据
  • state的基本使用

07-类组件提供状态

import { Component } from 'react'
import ReactDOM from 'react-dom'

/* 
  给类组件提供状态
*/
class App extends Component {
  constructor() {
    super()
    // 给this增加一个属性 state
    this.state = {
      msg: 'hello',
      count: 0,
    }
  }
  render() {
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.msg}</div>
        <div>{this.state.count}</div>
      </div>
    )
  }
}

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

在这里插入图片描述
09-类组件-提供状态简写

import { Component } from 'react'
import ReactDOM from 'react-dom'

/* 
  给类组件提供状态
*/
class App extends Component {
  // constructor() {
  //   super()
  //   // 给this增加一个属性 state
  //   this.state = {
  //     msg: 'hello',
  //     count: 0,
  //   }
  // }
  state = {
    msg: 'hello',
    count: 0,
  }
  render() {
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.msg}</div>
        <div>{this.state.count}</div>
        <button>+1</button>
      </div>
    )
  }
}

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

在这里插入图片描述

3 事件处理

3.1 注册事件

React注册事件与DOM的事件语法非常像
语法on+事件名={事件处理程序} 比如onClick={this.handleClick}
注意:React事件采用驼峰命名法,比如onMouseEnter, onClick

class App extends React.Component {
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }

  handleClick() {
    console.log('点击事件触发了')
  }
}

3.2 事件对象

可以通过事件处理程序参数获取到事件对象

function handleClick(e) {
    e.preventDefault()
    console.log('事件对象', e)
}
<a onClick={this.handleClick}>点我,不会跳转页面</a>

3.3 指向问题

事件处理程序中的this指向的是undefined

render方法中的this指向的而是当前react组件。只有事件处理程序中的this有问题

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }
}

例子:
10-类组件-注册事件的基本使用

import { Component } from 'react'
import ReactDOM from 'react-dom'
class App extends Component {
  state = {
    count: 0,
  }

  render() {
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.count}</div>
        <button onClick={this.clickFn} onMouseEnter={this.mouseFn}>
          +1
        </button>
        <a href="http://www.baidu.com" onClick={this.clickFn}>
          百度一下
        </a>
      </div>
    )
  }

  clickFn(e) {
    //e.preventDefault()会阻止表单提交的时候 重新加载页面。
    e.preventDefault()
    //e.stopPropagation()阻止事件冒泡。
    e.stopPropagation()
    console.log('点击事件')
  }
  mouseFn() {
    console.log('鼠标进入事件')
  }
}

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

在这里插入图片描述
在这里插入图片描述
11-类组件-事件中的this问题

import { Component } from 'react'
import ReactDOM from 'react-dom'
class App extends Component {
  state = {
    count: 0,
  }

  render() {
    console.log('render', this)
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.count}</div>
        <button onClick={this.clickFn}>+1</button>
      </div>
    )
  }

  clickFn() {
    console.log(this)
    console.log('点击事件')
    console.log(this.state.count)
  }
}

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

在这里插入图片描述
在这里插入图片描述

3.4 this指向问题解决方案

3.4.1 在render中使用箭头函数

箭头函数的特点:自身没有this,访问的是外部的this
方式1:

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  render() {
    return (
      <div>
        <button onClick={() => { console.log(this.state.msg) }>点我</button>
      </div>
    )
  }
}

缺点:会把大量的js处理逻辑放到JSX中,将来不容易维护
方式2

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={() => {this.handleClick()}}>点我</button>
      </div>
    )
  }
}

缺点:把大量的js逻辑写在了JSX结构中,不好维护

3.4.2 bind修改this指向

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>点我</button>
      </div>
    )
  }
}

或者

class App extends React.Component {
  constructor() {
  	super()
    this.handleClick = this.handleClick.bind(this)
  }
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }
}

3.4.3 class实例方法

class App extends React.Component {
  state = {
    msg: 'hello react'
  }

  handleClick = () => {
    console.log(this.state.msg)
  }
  render() {
    return (
      <div>
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }
}

注意:这个语法是试验性的语法,但是有babel的转义,所以没有任何问题

例子:

import { Component } from 'react'
import ReactDOM from 'react-dom'

class App extends Component {
  state = {
    count: 0,
  }

  // 在类组件中render的this不会有问题,,,this就指向当前组件

  // 解决react类组件中注册事件的this问题
  // 1. 把函数调用包裹在箭头函数中
  //      原本写法: onClick={this.clickFn}
  //      写法       onClick={() => this.clickFn()}

  // 2. 使用bind修改this的指向
  //          onClick={this.clickFn}
  //      bind优化   onClick={this.clickFn.bind(this)}

  // 3. class新语法: 类实例语法
  //      onClick={this.clickFn}
  //     把方法写法修改一下   clickFn = () => { console.log(this)  }
  render() {
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.count}</div>
        <button onClick={this.clickFn}>+1</button>
      </div>
    )
  }
  clickFn = () => {
    console.log('123', this)
  }
}

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

在这里插入图片描述
在这里插入图片描述

4 setState修改状态

  • 组件中的状态是可变的

  • 语法this.setState({要修改的数据})

  • 注意:不要直接修改state中的值,必须通过this.setState()方法进行修改

  • setState的作用

    • 修改state
    • 更新UI
  • 思想:数据驱动视图

import { Component } from 'react'
import ReactDOM from 'react-dom'

/* 
  给类组件提供状态
*/
class App extends Component {
  state = {
    count: 0,
    list: ['张三', '李四', '王五'],
  }
  render() {
    return (
      <div>
        <h1>我是根组件</h1>
        <div>{this.state.count}</div>
        <ul>
          {this.state.list.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
        <button onClick={this.clickFn}>+1</button>
        <button onClick={this.add}>增加数据</button>
      </div>
    )
  }
  /* 
    vue:
      vue会通过es5的语法Object.defineProperty()  vue3.0 会通过es6的proxy语法 监测到数据的改变,,,当数据改变的时候,vue会帮助我们自动更新DOM
      使用vue的时候,只需要直接修改数据即可。
      
    react: 
      react并不会去监听数据的变化,,,所以直接修改数据,react不知道。DOM就不会自动更新。
      react提供了一个方法,,,setState
      这个方法有两个作用:1.修改state的值 2. 更新DOM
    
    结论:
      1. react中不能直接修改state中的数据
      2. react中必须使用setState去修改数据。
  
  */
  clickFn = () => {
    // console.log(this.state.count)
    // this.state.count++
    // console.log(this.state.count)

    this.setState({
      count: this.state.count + 1,
    })
  }

  add = () => {
    this.setState({
      list: [...this.state.list, '赵六'],
    })
  }
}

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

在这里插入图片描述

4.1 react中核心理念:状态不可变

  • 不要直接修改react中state的值,而是提供新的值
  • 直接修改react中state的值,组件并不会更新

5.表单处理

我们在开发过程中,经常需要操作表单元素,比如获取表单的值或者是设置表单的值。

react中处理表单元素有两种方式:

  • 受控组件
  • 非受控组件(DOM操作)

5.1 受控组件基本概念

  • HTML中表单元素是可输入的,即表单用户并维护着自己的可变状态(value)。

  • 但是在react中,可变状态通常是保存在state中的,并且要求状态只能通过setState进行修改。

  • React中将state中的数据与表单元素的value值绑定到了一起,由state的值来控制表单元素的值

  • 受控组件:value值受到了react控制的表单元素
    在这里插入图片描述

5.2 受控组件使用步骤

  1. 在state中添加一个状态,作为表单元素的value值(控制表单元素的值)
  2. 给表单元素添加change事件,设置state的值为表单元素的值(控制值的变化)
class App extends React.Component {
  state = {
    msg: 'hello react'
  }

  handleChange = (e) => {
    this.setState({
      msg: e.target.value
    })
  }

  render() {
    return (
      <div>
        <input type="text" value={this.state.msg} onChange={this.handleChange}/>
      </div>
    )
  }
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值