React基础知识整理学习二

570 阅读6分钟

什么是组件,组件的特点及分类

组件

组件是指对特定功能的封装,主要用来对UI进行拆分。

特点

  • 独立
  • 可复用
  • 可组合

分类

  • 基础组件:指inputbutton这种基础标签,以及antd封装过的通用UI组件
  • 业务组件:由基础组件组合成的业务抽象化UI。例如: 包含了A公司所有部门信息的下拉框
  • 区块组件:由基础组件组件和业务组件组合成的UI块
  • 页面组件:展示给用户的最终页面,一般就是对应一个路由规则

React 组件的两种创建方式

(1)使用 JS 中的函数创建组件

(2)使用 JS 中的 class 创建组件

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

const title = <h1>react的两种定义组件的方式</h1>

// 定义一个函数式组件
const Com1 = () => {
  return <div>第一个函数式组件</div>
}

// 定义一个类组件
class Com2 extends React.Component {
  render () {
    return <div>第一个类组件</div>
  }
}

const content = (
  <div>
    {title}
    // 使用双标签渲染
    <Com1></Com1>
    <hr />
    // 使用单标签渲染
    <Com2 />
  </div>
)

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

函数式组件-使用 JS 的函数(或箭头函数)创建的组件

默认约定

  • 函数名首字符大写(必须以大写字母开头,React 据此区分组件普通的 HTML)
  • 必须有返回值(表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null)
// 1. 使用普通函数创建组件:
function Hello() {
  return <div>这是我的第一个函数组件!</div>
}

// 2.  使用箭头函数创建组件:
const Hello = () => <div>这是我的第一个函数组件!</div>

类组件-用class创建组件

格式

// import { Component } from 'react'
// class 类名 extends Component {
import React form 'react'
class 类名 extends React.Component {
  // ... 
  render () {
    return 本组件的UI结构
  }
}

注意点

  • 类名必须以大写字母开头
  • extends是一个关键字,用来实现类之间的继承。类组件应该继承 React.Component 父类,从而使用父类中提供的方法或属性。
  • 类组件必须提供 render 方法,render 方法必须有返回值,表示该组件的 UI 结构。render会在组件创建时执行一次

有状态组件和无状态组件

什么是状态(state)

状态是指用来描述事物在某一时刻的形态的数据.(例如:11月12日时书的库存数量)

特点

状态能被改变,改变了之后视图会有对应的变化

什么是有状态组件和无状态组件

  • 有状态组件:能定义state的组件。类组件就是有状态组件。

  • 无状态组件:不能定义state的组件。函数组件又叫做无状态组件 (注:2019年02月06日,react 16.8中引入了 React Hooks,从而函数式组件也能定义自己的状态了)

类组件的状态

定义状态的两种方式

(1)state = 对象

(2)在构造器中用this.state= 对象来做初始化

import React from "react";
export default class Hello extends React.Component {
  // 1. state就是状态
  state = {
    list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
    isLoading: true
  };
  // 2. 构造函数
  constructor() {
    this.state = {
      list: [{ id: 1, name: "明天会更好" },{ id: 2, name: "难忘今宵" }],
      isLoading: true
    }
  }
}

在视图中使用

  render() {
    return (
      <>
        <h1>歌单-{this.state.count}</h1>
        <ul>
          {this.state.list.map((item) => (
            <li key={item.id}>{item.name}</li>
          ))}
        </ul>
        <div>{this.state.isLoading ? "正在加载" : "加载完成"}</div>
      </>
    );
  }

事件绑定

格式

<元素 事件名1={ 事件处理函数1 } 事件名2={ 事件处理函数2 } ></元素>

(注:React 事件名采用驼峰命名法,比如:onMouseEnter、onFocus、 onClick ......)

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

const title = <h1>react中的事件</h1>


export default class Hello extends React.Component {
  fn() {
    console.log('mouseEnter事件')
  }
  render() {
    return (
      <div
        onClick={() => console.log('click事件')}
        onMouseEnter={this.fn}
        能处理鼠标进入或者点击事件
      </div>
    )
  }
}

const content = (
  <div>
    {title}
    {<Hello />}
  </div>
)

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

注意:

  • 事件名是小驼峰命名格式
  • 在类中补充方法
  • this.fn不要加括号

事件对象

react中,通过事件处理函数的形参来获取。

  handleClick(e)=> {
    e.preventDefault()
    console.log('单击事件触发了', e)
  }
	render() {
  	return (<div>
            <button onClick={(e)=>{console.log('按钮点击了', e)}}>按钮</button>
    				<a href="http://itcast.cn/" onClick={this.handleClick}>武汉黑马</a>
  			</div>)  
  }
}

事件处理-this指向问题

class App extends React.Component {
  state = {
    msg: 'hello react'
  }
  handleClick() {
    console.log(this) // 这里的this是?undefined
  }
  render() {
    console.log(this) // 这里的this是?当前react组件
    return (
      <div>
      //this.handleClick并没有调用,其没有绑定调用的事件源,在严格模式下指向的并不是window
        <button onClick={this.handleClick}>点我</button>
      </div>
    )
  }
}

分析原因

  • 事件处理程序的函数式函数调用模式,在严格模式下,this指向undefined
  • render函数是被组件实例调用的,因此render函数中的this指向当前组件

事件处理-this指向解决方案

(1)在外层补充箭头函数(原理:箭头函数中的this指向外层作用域中的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>
    )
  }
}

(2)Function.prototype.bind()(原理: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>
    )
  }
}

(3)class 的实例方法【推荐】

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

组件的状态-修改状态

setState

语法:this.setState({ 要修改的部分数据 })

作用: 修改state; 更新UI

state = {
  count: 0 
};

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

注: react核心理念之状态不可变

不要直接修改当前状态值,而是创建新的状态值去覆盖老的值。

获取表单元素的值的两种思路

  • 直接找到表单元素进行dom操作 --> 非受控组件
  • 将表单元素值与react的state绑定到一起,把用户的修改同步到state中。让组件受到react的控制--> 受控组件

非受控组件-ref

使用步骤:

(1)导入方法。import { createRef } from 'react'

(2)调用createRef方法创建引用,假设名为refDom。 const refDom = createRef()

(3)refDom设置给表单元素的ref属性。<input ref={refDom}/>

(4)通过refDom.current.value来获取值。console.log(this.refDom.current.value)

// 1. 导入方法
import { createRef } from 'react'

class Hello extends Component {
  // 2. 调用createRef方法创建引用
  txtRef = createRef()

  handleClick = () => {
    // 4. 通过.current.value来获取值
    console.log(this.txtRef.current.value)
  }

  render() {
    return (
      <div>
      	<h1>如何获取input中的值-非受控组件-ref</h1>
         {/* 3. 设置给表单元素的ref属性 */}
        <p><input type="text" ref={this.txtRef}/></p>
        <button onClick={handleClick}>获取文本框的值</button>
      <div>
    )
  }
}

受控组件

使用步骤:

  • 在state中定义状态

  • 对表单元素做两件事

    (1)设置value为上面定义的状态

    (2)绑定onChange事件,并在回调中通过setState来修改状态值

class App extends React.Component {
  state = {
    // 1. 在state中定义状态
    msg: 'hello react'
  }

  handleChange = (e) => {
    this.setState({
      msg: e.target.value
    })
  }
  
  handleClick = ()=> {
    console.log(this.state.msg)
  }

  render() {
    return (
      <div>
      	<h1>如何获取input中的值-受控组件</h1>
        <p>
        {/* 2. 对表单元素做两件事 */}
          	<input type="text"
							value={this.state.msg}
							onChange={this.handleChange}
						/>
        </p>
        <button onClick={handleClick}>获取文本框的值</button>
      <div>
    )
  }
}

常见的受控组件

不同类型的表单元素进行受控处理时的格式是不同的:

(1)文本框、文本域、下拉框:value属性 + onChange事件

(2)复选框: checked属性 + onChange事件

(3)单选按钮组:checked属性 + onChange事件

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

class App extends React.Component {
  state = {
    username: '',
    desc: '',
    city: '2',
    isSingle: true,
    gender: '男'
  }

  handleName = (e) => {
    this.setState({
      username: e.target.value
    })
  }

  handleDesc = (e) => {
    this.setState({
      desc: e.target.value
    })
  }

  handleCity = (e) => {
    this.setState({
      city: e.target.value
    })
  }

  handleSingle = (e) => {
    this.setState({
      isSingle: e.target.checked
    })
  }

  hGender = (e) => {
    this.setState({
      gender: e.target.value
    })
  }

  render () {
    return (
      <div>
        姓名:<input
          type="text"
          value={this.state.username}
          onChange={this.handleName}
        />
        <br />
        描述:<textarea value={this.state.desc} onChange={this.handleDesc} />
        <br />
        城市:<select value={this.state.city} onChange={this.handleCity}>
          <option value="1">北京</option>
          <option value="2">上海</option>
          <option value="3">广州</option>
          <option value="4">深圳</option>
        </select>
        <br />
        是否单身:<input
          type="checkbox"
          checked={this.state.isSingle}
          onChange={this.handleSingle}
        />
        <br />
        <input
          type="radio"
          name="gender"
          value="男"
          checked={this.state.gender === '男'}
          onChange={this.hGender}
        />{' '}
        男
        <input
          type="radio"
          name="gender"
          value="女"
          checked={this.state.gender === '女'}
          onChange={this.hGender}
        />{' '}
        女
      </div>
    )
  }
}

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