02-component

Component – React 中文文档open in new window

1. 概念

一个组件就是一个用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以服用多次

ZDdQbUxhTUpjYS9NdUdsdHZxdU9QdmowTk44RnhubGZNVVhwZ1czL1RBPT0=

2. 基础使用

在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI, 渲染组件只需要把组件当成标签书写即可

// 1. 定义组件
function Button() {
  return <button>click me</button>
}

// 2. 使用组件
function App() {
  return (
      <div>
        {/* 自闭和 */}
        <Button/>
        {/* 成对标签 */}
        <Button></Button>
      </div>
  )
}

 








 





2. 状态管理

1. 基础使用

useState 是一个 React Hook(函数),它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果

和普通 JS 变量不同的是,状态变量一旦发生变化组件的视图 UI 也会跟着变化(数据驱动视图)

RW5uR2xiLzd6RzR6dnJ4d0crbTNzdmowTk44RnhubGZNVVhwZ1czL1RBPT0=
import React from "react";

function App() {

  const [count, setCount] = React.useState(0)

  return (
      <div>
        <button onClick={() => setCount(count + 1)}>{count}</button>
      </div>
  )
}




 



 



2. 状态的修改规则

在 React 中状态被认为是只读的,应该始终 替换它而不是修改它,直接修改状态不能引发视图更新

function App() {

  let [count, setCount] = React.useState(0)

  const handleClick = () => {
    // 直接修改,无法引发视图更新
    count++;
    console.log(count)
  }

  return (
      <div>
        <button onClick={handleClick}>{count}</button>
      </div>
  )
}


 



 





 



function App() {

  let [count, setCount] = React.useState(0)

  const handleClick = () => {
    // 作用:
    // 1. 用传入的新值修改 count
    // 2. 重新使用新的 count 渲染 UI
    setCount(count + 1)
  }

  return (
      <div>
        <button onClick={handleClick}>{count}</button>
      </div>
  )
}


 





 




 



3. 修改对象状态

对于对象类型的状态变量,应该始终给 setter() 一个 全新的对象 来进行修改

import React, {useState} from "react";

function App() {
  const [form, setForm] = useState({
    name: 'jack',
  })

  const handleChangeName = () => {
    // 直接修改原对象,不引发视图变化
    form.name = 'john'
  }

  return (
      <div>
        <button onClick={handleChangeName}>{form.name}</button>
      </div>
  )
}



 





 




 



import React, {useState} from "react";

function App() {

  const [form, setForm] = useState({
    name: 'jack',
  })

  const handleChangeName = () => {
    // 调用 set 传入新对象用于修改
    setForm({
      ...form,
      name: 'john',
    })
  }

  return (
      <div>
        <button onClick={handleChangeName}>{form.name}</button>
      </div>
  )
}










 
 
 
 








3. 基础样式处理

React 组件基础的样式控制有两种方式,行内样式、class 类名控制

function App() {
  return (
      <div>
        <div style={{color: 'red'}}>this is div</div>
      </div>
  )
}



 



const ooxx = {
  color: 'red'
}

function App() {
  return (
      <div>
        <div style={ooxx}>this is div</div>
      </div>
  )
}
 






 



.foo {
  color: red;
}
import './index.css'

function App(){
  return (
      <div>
        <span className="foo">this is span</span>
      </div>
  )
}
 




 



4. 自增组件

Counter 自增组件,看一下组件的基础编写结构

import {Component} from 'react'

class Counter extends Component {
  // 状态变量
  state = {
    count: 0,
  }

  // 事件回调
  clickHandler = () => {
    // 修改状态变量,触发 UI 组件渲染
    this.setState({
      count: this.state.count + 1,
    })
  }

  // UI模版
  render() {
    return <button onClick={this.clickHandler}>+{this.state.count}</button>
  }
}

function App() {
  return (
      <div>
        <Counter/>
      </div>
  )
}

export default App


 








 






 






 





5. 生命周期

概念:组件从创建到销毁的各个阶段自动执行的函数就是生命周期函数

  1. componentDidMount:组件挂载完毕自动执行 —— 异步数据获取
  2. componentWillUnmount:组件卸载时自动执行 —— 清理副作用
SlQyeDZ3aG5Td2RTa2hSUVF6QUM0dEtOcmlZUDZiTy83TGJmVUtzPQ==

6. 组件通信

概念:组件通信就是 组件之间的数据传递,根据组件嵌套关系的不同,有不同的通信手段和方法

eTMvMHNGZnkyUlJzWmR2T3l6cFdhL2owTk44RnhubGZNVVhwZ1czL1RBPT0=
  1. A-B:父子通信
  2. B-C:兄弟通信
  3. A-E:跨层通信

1. 父传子

Nzc5eDM3NTd5NE9aNkZMMkdTR1VidmowTk44RnhubGZNVVhwZ1czL1RBPT0=

1. 基础实现

  1. 父组件传递数据:在子组件标签上绑定属性
  2. 子组件接收数据:子组件通过props参数接收数据
function Son(props) {
  return <div>{props.name}</div>
}


function App() {
  const name = 'this is app name'
  return (
      <div>
        <Son name={name}/>
      </div>
  )
}
 








 



import {Component} from 'react'

class Son extends Component {
  render() {
    const {count} = this.props
    return <div>this is Son, {count}</div>
  }
}

class App extends Component {
  // 状态变量
  state = {
    count: 0,
  }

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

  // UI 模版
  render() {
    return (
        <>
          <Son count={this.state.count}/>
          <button onClick={this.setCount}>+</button>
        </>
    )
  }
}

export default App




 




















 







2. props说明

props 可以传递任意的合法数据。props 是只读对象

  • 数字
  • 字符串
  • 布尔值
  • 数组
  • 对象
  • 函数
  • JSX
function Son(props) {
  console.log(props)
  return <div>{props.name}</div>
}

const appName = 'this is app name';

function App() {
  const name = 'this is app name'
  return (
      <div>
        <Son
            name={appName}
            age={20}
            isTrue={false}
            list={['Vue', 'React']}
            obj={{name: 'jack'}}
            cb={() => console.log(123)}
            child={<span>this is span child</span>}
        />
      </div>
  )
}












 
 
 
 
 
 
 




NFR0WHRBUDBJanIydjN1dXluM2hJZmowTk44RnhubGZNVVhwZ1czL1RBPT0=

3. 特殊prop-children

场景:当把内容嵌套在组件的标签内部时,组件会自动在名为 children 的 prop 属性中接收该内容

ajNkTzA1ZkU5aWFvNDl0QTB1R2Q2UGowTk44RnhubGZNVVhwZ1cwPQ==

2. 子传父

NGt4V0l1Ni9Td0gwcjZCZ21wM3oxZmowTk44RnhubGZNVVhwZ1czL1RBPT0=

核心思路:在子组件中,调用父组件中的函数并传递参数

function Son({onGetMsg}) {
    const sonMsg = 'this is son msg'
    return (
        <div>
            {/* 在子组件中执行父组件传递过来的函数 */}
            <button onClick={() => onGetMsg(sonMsg)}>send</button>
        </div>
    )
}

function App() {
    const getMsg = (msg) => console.log(msg)

    return (
        <div>
            {/* 传递父组件中的函数到子组件 */}
            <Son onGetMsg={getMsg}/>
        </div>
    )
}
 




 










 



import {Component} from 'react'

class Son extends Component {
  render() {
    const {msg, onGetSonMsg} = this.props
    return (
        <>
          <div>this is Son, {msg}</div>
          <button onClick={() => onGetSonMsg('this is son msg')}>
            changeMsg
          </button>
        </>
    )
  }
}

class App extends Component {
  // 状态变量
  state = {
    msg: 'this is initail app msg',
  }

  onGetSonMsg = (msg) => {
    this.setState({msg})
  }

  // UI 模版
  render() {
    return (
        <>
          <Son msg={this.state.msg} onGetSonMsg={this.onGetSonMsg}/>
        </>
    )
  }
}

export default App




 



 





















 






3. 兄弟组件

L3V2MUJoeEpFUWdaKzAybnluTGpmUGowTk44RnhubGZNVVhwZ1czL1RBPT0=

实现思路:借助 状态提升 机制,通过共同的父组件进行兄弟之间的数据传递

  1. 通过子传父:A -> App
  2. 通过父传子:App -> B
import {useState} from 'react'

function A({onGetAName}) {
  // Son 组件中的数据
  const name = 'A.msg'
  return (
      <div>
        this is A component =>
        <button onClick={() => onGetAName(name)}>send</button>
      </div>
  )
}

function B({name}) {
  return (
      <div>
        this is B component => receive =>
        {name}
      </div>
  )
}

function App() {
  const [name, setName] = useState('')

  const getAName = (name) => {
    setName(name)
  }

  return (
      <div>
        this is App
        <A onGetAName={getAName}/>
        <B name={name}/>
      </div>
  )
}

export default App








 








 














 
 





4. 跨层组件

L2dkUFJXQm1qRW53ZnNnM0pHYkVOL2owTk44RnhubGZNVVhwZ1czL1RBPT0=
  1. 使用 createContext() 创建一个上下文对象 Ctx
  2. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据
  3. 在底层组件(B)中通过 useContext 钩子函数获取消费数据
  4. App -> A -> B
import {createContext, useContext} from "react"

// 1. createContext() 创建一个上下文对象
const MsgContext = createContext()

function A() {
  return (
      <div>
        this is A component
        <B/>
      </div>
  )
}

function B() {
  // 3. 在底层组件。通过 useContext 钩子函数使用数据
  const msg = useContext(MsgContext)
  return (
      <div>
        this is B component => {msg}
      </div>
  )
}

function App() {
  const msg = 'this is app msg'
  return (
      <div>
        {/* 2. 在顶层组件。通过 Provider 组件提供数据 */}
        <MsgContext.Provider value={msg}>
          this is App
          <A/>
        </MsgContext.Provider>
      </div>
  )
}

export default App