深入浅出 React 组件

简介: 组件是 React 的一等公民,使用 React 就是在用组件。

深入浅出 React 组件


React 组件介绍


  1. 组件是 React 的一等公民,使用 React 就是在用组件。


  1. 组件表示页面中的部分功能。


  1. 组合多个组件实现完整的页面功能。


  1. 特点:
  • 可复用。
  • 独立性。
  • 可组合。


React 组件的两种创建方式


使用函数创建组件:


  1. 函数组件:使用 JS 的函数(或建瓯函数)创建的组件


  • 约定一:函数名称必须以大写字母开头。
  • 约定二:函数组件必须有返回值,表示该组件的结构。
  • 如果返回值是 null ,表示不渲染任何内容。
function Hello () {
  return (
    <div>这是我的第一个函数组件!</div>
  )
}

2.渲染函数组件:用函数名作为组件标签名。


  • 组件标签可以是单标签也可以是双标签。
function Hello () {
  return (
    <div>这是我的第一个函数组件!</div>
  )
}
// 渲染
ReactDOM.render(<Hello />, document.querySelector('#root')

用箭头函数创建组件:

const Hello = () => <div>这是我的第一个函数组件</div>
// 这个渲染的效果等同于上面的那个函数创建的组件。

3.总结:


  • 使用 JS 中的函数创建的组件叫做:函数组件
  • 函数组件必须有返回值。
  • 组件名称必须以大写字母开头,React 据此区分 组件 和 普通的 React 元素。
  • 使用函数名作为组件标签名。


使用类创建组件:


  1. 类组件:使用 ES6 的 class 创建的组件。


  • 约定一:类名称也必须以大写字母开头。
  • 约定二:类组件应该继承 React.Component 父类,从而可以使用父类中提供的方法或属性。
  • 约定三:类组件必须提供 render() 方法。
  • 约定四:render() 方法必须有返回值,表示该组件的结构。
class Hello extends React.Component {
  render () {
    return <div>Hello Class Component!</div>
  }
}
ReactDOM.render(<Hello />, document.querySelector('#root')


抽离为独立 JS 文件


  1. 思考:项目中的组件多了以后,该如何组织这些组件呢?


  • 选择一:将所有组件放在同一个 JS 文件中。
  • 选择二:将每个组件放到单独的 JS 文件中。


  1. 组件作为一个独立的个体,一般都会放到一个单独的 JS 文件中


  1. 抽离组件的步骤:


  • 创建 Hello.js 文件。
  • 在 Hello.js 中导入 React 。
  • 创建组件(函数组件或类组件)。
  • 在 Hello.js 中导出该组件。
  • 在 index.js 中导入 Hello 组件。
  • 渲染组件。
// Hello.js 文件
import React from 'react'
class Hello extends React.Component {
  render () {
    return <div>Hello Class Component!</div>
  }
}
// 导出 Hello 组件
export default Hello
// index.js 文件
import Hello from './Hello'
// 渲染导入的 Hello 组件
ReactDOM.render(<Hello />, document.querySelector('#root')


React 事件处理


事件绑定


  1. React 事件绑定语法与 DOM 事件语法相似。


  1. 语法:


  • on + 事件名称 = {事件处理程序}
  • 比如:onClick={() => {}}


3.注意:**React 事件采用驼峰命名法,比如:onMouseEnter、onFocus 。

// 通过类创建组件
class App extends React.Component {
  handleClick() {
    console.log('单击事件触发了')
  }
  render() {
    return (
      <button onClick={this.handleClick}>点我</button>
    )
  }
}
// 通过函数创建组件
function App () {
  function handleClick() {
    console.log('单击事件触发了')
  }
  return (
      <button onClick={this.handleClick}>点我</button>
    )
}


事件对象


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


  1. React 中的事件对象叫做:合成事件(对象)


  1. 合成事件:兼容所有浏览器,无需担心跨域浏览器兼容性问题。
function handleClick(e) {
  e.preventDefault()
  console.log('事件对象',e)
}
<a onClick={handleClick}>点我不会跳转页面</a>

4.具体使用:

function App() {
  function handleClick(e) {
    // 阻止浏览器的默认行为
    e.preventDefault()
    console.log('事件对象',e)
  }
  return(
    <a href="www.baidu.com" onClick={handleClick}>点击页面不跳转</a>
  )
}
// 渲染react元素
ReactDOM.render(<App />, document.querySelector('#root'))


有状态组件和无状态组件


  1. 函数组件又叫做无状态组件,类组件又叫做有状态组件


  1. 状态(state)即数据


  1. 函数组件没有自己的状态,只负责数据展示(静)。


  1. 类组件有自己的状态,负责更新 UI ,让页面“动”起来。


  • 比如计数器案例中,点击按钮让数值加1.0和1就是不同时刻的状态,而由0变1就表示状态发生了变化。状态变化后,UI 也要相应的更新。React 中想要实现该功能,就要使用有状态组件来完成。


组件中的 state 和 setState


state 的基本使用


  1. 状态(state)即数据,是组件内部的私有数据,只能在组件内部使用。


  1. state 的值是对象,表示一个组件中可以有多个数据。
class App extends React.Component {
  constyuctor() {
    super()
    // 初始化 state
    this.state = {
      count: 0
    }
  }
  // 简化写法(推荐)
  state = {
    count: 0
  }
  render(){
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
      </div>
    )
  }
}
ReactDOM.render(<App />, document.querySelector('#root'))

3.总结:


  • 状态即数据。
  • 状态是私有的,只能在组件内部使用。
  • 通过 this.state 来获取状态。


setState() 修改状态


  1. 状态是可变的。


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


  1. 注意:不要直接修改 state 中的值,这是错误的!!!
// 正确
this.setState({
  count: this.state.count + 1
})
// 错误
this.state.count += 1

4.setState() 的作用:

  • 修改 state 。
  • 更新 UI 。


5.思想:数据驱动视图


从 JSX 中抽离事件处理程序


  1. JSX 中掺杂过多 JS 逻辑代码,会显得非常混乱。


  1. 推荐:将逻辑抽离到单独的方法中,保证 JSX 结构清晰。

1.png

  1. 原因:事件处理程序中 this 的值为 undefined 。


  1. 希望:this 指向组件实例(render 方法中的 this 即为组件实例)


事件绑定 this 指向


箭头函数


  1. 利用箭头函数自身不绑定 this 的特点。


  1. render() 方法中的 this 为组件实例,可以获取到 setState() 。
class App extends React.Component {
  state = {
    count: 0
  }
  onIncrement() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    // 箭头函数中的 this 指向外部环境,此处为:render() 方法。
    return (
      <div>
        <h1>总数:{this.state.count}</h1>
        <button onClick={() => this.onIncrement()}>+1</button>
      </div>
    )
  }
}


Function.prototype.bind()


  1. 利用 ES5 中的 bind 方法,将事件处理程序中的 this 与组件实例绑定到一起。
class App extends React.Component {
  constructor() {
    super()
    this.state = {
      count: 0
    }
    this.onIncrement = this.onIncrement.bind(this)
  }
  onIncrement() {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    // 箭头函数中的 this 指向外部环境,此处为:render() 方法。
    return (
      <div>
        <h1>总数:{this.state.count}</h1>
        <button onClick={this.onIncrement}>+1</button>
      </div>
    )
  }
}


class 的实例方法


  1. 利用箭头函数形式的 class 实例方法。


  1. 注意:该语法是实验性语法,但是,由于 babel 的存在可以直接调用。
class App extends React.Component {
  state = {
    count: 0
  }
  onIncrement = () => {
    this.setState({
      count: this.state.count + 1
    })
  }
  render() {
    return (
      <div>
        <h1>总数:{this.state.count}</h1>
        <button onClick={this.onIncrement}>+1</button>
      </div>
    )
  }
}


总结


  1. 推荐:使用 class 的实例方法。
class Hello extends React.Component {
  onIncrement = () => {
    this.setState({...})
  }
}

2.箭头函数。

<button onClick={() => this.onIncrement()}>+1</button>

3.bind

constructor() {
  super()
  this.onIncrement = this.onIncrement.bind(this)
}


表单处理


受控组件


  1. HTML 中的表单元素是可输入的,也就是有自己的可变状态。


  1. 而 React 中可变状态通常保存在 state 中,并且只能通过 setState() 方法来修改。


  1. React 将 state 与表单元素的 value 绑定到了一起,由 state 的值来控制表单元素的值
<input type="text" value={this.state.txt} />

4.受控组件:其值受到 React 控制的表单元素。


5.步骤:


  • 在 state 中添加一个状态,作为表单元素的 value 值(控制表单元素值的来源)。
state = { txt: '' }
<input type="text" value={this.state.txt} />

给表单元素绑定 change 事件,将表单元素的值设置为 state 的值(控制表单元素值的变化)。

<input type="text" value={this.state.txt} onChange={e => this.setState({ txt: e.target.value })} />

6.实例:


  • 文本框
class App extends React.Component {
  state = {
    txt: ''
  }
  handleChange = e => {
    this.setState({
      txt: e.target.value
    })
  }
  render() {
    return (
      <div>
        <input type="text" value={this.state.txt} onChange={this.handleChange} />
        <h2>{this.state.txt}</h2>
      </div>
    )
  }
}

富文本框、下拉框

class App extends React.Component {
  state = {
    content: ''
  }
  handleContent = e => {
    this.setState({
      content: e.target.value
    })
  }
  render() {
    return (
      <div>
        <input type="text" value={this.state.content} onChange={this.handleContent} />
        <h2>{this.state.content}</h2>
      </div>
    )
  }
}

下拉框

class App extends React.Component {
  state = {
    city: 'sh'
  }
  handleCity = e => {
    this.setState({
      city: e.target.value
    })
  }
  render() {
    return (
      <div>
        <select value={this.state.city} onChange={this.handleCity}>
          <option value="bj">北京</option>
          <option value="sh">上海</option>
          <option value="gz">广州</option>
        </select>
        <h2>{this.state.city}</h2>
      </div>
    )
  }
}

复选框

class App extends React.Component {
  state = {
    isChecked: true
  }
  handleChecked = e => {
    this.setState({
      isChecked: e.target.checked
    })
  }
  render() {
    return (
      <div>
        <input type="checkbox" checked={this.state.isChecked} onChange={this.handleChecked} />
      </div>
    )
  }
}


示例总结


  1. 文本框、富文本框、下拉框操作 value 属性。


  1. 复选框操作 checked 属性。


多表单元素优化


  1. 问题:每个表单元素都有一个单独的事件处理程序处理太繁琐。
  • 优化:使用一个事件处理程序同时处理多个表单元素。


  1. 步骤:
  • 给表单元素添加 name 属性,名称与 state 相同。
<input
  type="text"
  name="txt"
  value={this.state.txt}
  onChange={this.handleForm}
/>

根据表单元素类型获取对应值。

// 根据表单元素类型获取值
const value = target.type === 'checkbox' ? target.checked : target.value
// 根据 name 设置对应 state
this.setState({
  [name]: value
})
  • 在 change 事件处理程序中通过 [name] 来修改对应的 state 。


  1. 实例:
class App extends React.Component {
  state = {
    txt: '',
    content: '',
    city: 'sh',
    isChecked: true
  }
  handleForm = e => {
    // 获取当前 DOM 对象
    const target = e.target
    // 根据类型获取值
    const value = target.type === 'checkbox' ? target.checked : target.value
    // 获取 name
    const name = target.name
    this.setState({
      [name]: value
    })
  }
  render() {
    return (
      <div>
        <input name="txt" type="text" value={this.state.txt} onChange={this.handleForm} />
        <br/>
        <h1>{this.state.txt}</h1>
        <textarea name="content" type="checkbox" checked={this.state.content} onChange={this.handleForm} />
        <br/>
        <h1>{this.state.content}</h1>
        <select name="city" value={this.state.city} onChange={this.handleForm}>
          <option value="bj">北京</option>
          <option value="sh">上海</option>
          <option value="gz">广州</option>
        </select>
        <br/>
        <h1>{this.state.city}</h1>
        <input name="isChecked" type="checkbox" checked={this.state.isChecked} onChange={this.handleForm} />
        <br/>
        <h1>{this.state.isChecked}</h1>
      </div>
    )
  }
}


非受控组件


  1. 使用步骤:


  • 调用 React.createRef() 方法创建一个 ref 对象。
constructor() {
  super()
  this.txtRef = React.createRef()
}

将创建好的 ref 对象添加到文本框中。

<input type="text" ref={this.txtRef} />

通过 ref 对象获取到文本框的值。

console.log(this.txtRef.current.value)
  • 大多数情况下使用受控组件。


总结


  1. 组件的两种创建方式:函数组件和类组件。
  2. 无状态(函数)组件,负责静态结构展示。
  3. 有状态(类)组件,负责更新 UI ,让页面动起来。
  4. 绑定事件注意 this 指向。
  5. 推荐使用受控组件来处理表单。
  6. 完全利用 JS 语言的能力创建组件,这是 React 的思想。
相关文章
|
4月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
294 0
|
4月前
|
存储 前端开发 JavaScript
【第34期】一文学会React组件传值
【第34期】一文学会React组件传值
64 0
|
4月前
|
前端开发
【第31期】一文学会用React Hooks组件编写组件
【第31期】一文学会用React Hooks组件编写组件
63 0
|
4月前
|
存储 前端开发 JavaScript
【第29期】一文学会用React类组件编写组件
【第29期】一文学会用React类组件编写组件
65 0
|
4月前
|
前端开发 开发者
【第26期】一文读懂React组件编写方式
【第26期】一文读懂React组件编写方式
51 0
|
4月前
|
资源调度 前端开发 JavaScript
React 的antd-mobile 组件库,嵌套路由
React 的antd-mobile 组件库,嵌套路由
98 0
|
4月前
|
存储 前端开发 中间件
React组件间的通信
React组件间的通信
40 1
|
4月前
|
前端开发 JavaScript API
React组件生命周期
React组件生命周期
103 1
|
4月前
|
存储 前端开发 JavaScript
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)
探索 React Hooks 的世界:如何构建出色的组件(下)
|
4月前
|
缓存 前端开发 API
探索 React Hooks 的世界:如何构建出色的组件(上)
探索 React Hooks 的世界:如何构建出色的组件(上)
探索 React Hooks 的世界:如何构建出色的组件(上)