Skip to content

Day2

2.1 受控表单绑定

受控绑定

jsx
function App(){
  const [value, setValue] = useState('')
  return (
    <input 
      type="text" 
      value={value} 
      onChange={e => setValue(e.target.value)}
    />
  )
}

非受控绑定useRef

jsx
function App(){
  const inputRef = useRef(null)

  const onChange = ()=>{
    console.log(inputRef.current.value)
  }
  
  return (
    <input 
      type="text" 
      ref={inputRef}
      onChange={onChange}
    />
  )
}

2.2 组件通信

2.2.1 父传子-基础实现

实现步骤

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


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

props说明

  1. props可以传递任意的合法数据,比如数字、字符串、布尔值、数组、对象、函数、JSX
  2. props是只读对象 子组件只能读取props中的数据,不能直接进行修改, 父组件的数据只能由父组件修改
jsx
<Son
name={appName}
age = {20}
isTrue = {false}
list = {['Vue','React']}
obj={{name:'jack'}}
cb={()=>console.log(123)}
child = {<span?>this is span child</span>}
/>

特殊的prop children

return {props.children}

jsx
<Son>
  <span>this is span</span>
</Son>

2.2.2 子传父

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

jsx
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>
  )
}

2.2.3 兄弟组件通信

提示

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

  1. A组件先通过子传父的方式把数据传递给父组件App
  2. App拿到数据之后通过父传子的方式再传递给B组件
jsx

// 1. 通过子传父 A -> App
// 2. 通过父传子 App -> B

import { useState } from "react"

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

function B ({ name }) {
  return (
    <div>
      this is B compnent,
      {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

2.2.4 跨层组件通信

实现步骤:

  1. 使用 createContext方法创建一个上下文对象Ctx
  2. 在顶层组件(App)中通过 Ctx.Provider 组件提供数据
  3. 在底层组件(B)中通过 useContext 钩子函数获取消费数据
jsx
// 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 compnent,{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

2.3 useEffect的使用

概念: useEffect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作(副作用), 比 如发送AJAX请求,更改DOM等等

jsx
useEffect(()=>{},[])

说明:

  1. 参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作
  2. 参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次

2.3.1 依赖说明

依赖项副作用功函数的执行时机
没有依赖项组件初始渲染 + 组件更新时执行
空数组依赖只在初始渲染时执行一次
添加特定依赖项组件初始渲染 + 依赖项变化时执行

2.3.2 清除副作用

jsx
import { useEffect, useState } from "react"

function Son () {
  // 1. 渲染时开启一个定时器
  useEffect(() => {
    const timer = setInterval(() => {
      console.log('定时器执行中...')
    }, 1000)

    return () => {
      // 清除副作用(组件卸载时)
      clearInterval(timer)
    }
  }, [])
  return <div>this is son</div>
}

function App () {
  // 通过条件渲染模拟组件卸载
  const [show, setShow] = useState(true)
  return (
    <div>
      {show && <Son />}
      <button onClick={() => setShow(false)}>卸载Son组件</button>
    </div>
  )
}

export default App

警告

说明:清除副作用的函数最常见的执行时机是在组件卸载时自动执行

2.4 Hook

2.4.1 自定义Hook实现

概念:自定义Hook是以 use打头的函数,通过自定义Hook函数可以用来实现逻辑的封装和复用

jsx
// 封装自定义Hook

// 问题: 布尔切换的逻辑 当前组件耦合在一起的 不方便复用

// 解决思路: 自定义hook

import { useState } from "react"

function useToggle () {
  // 可复用的逻辑代码
  const [value, setValue] = useState(true)

  const toggle = () => setValue(!value)

  // 哪些状态和回调函数需要在其他组件中使用 return
  return {
    value,
    toggle
  }
}

// 封装自定义hook通用思路

// 1. 声明一个以use打头的函数
// 2. 在函数体内封装可复用的逻辑(只要是可复用的逻辑)
// 3. 把组件中用到的状态或者回调return出去(以对象或者数组)
// 4. 在哪个组件中要用到这个逻辑,就执行这个函数,解构出来状态和回调进行使用


function App () {
  const { value, toggle } = useToggle()
  return (
    <div>
      {value && <div>this is div</div>}
      <button onClick={toggle}>toggle</button>
    </div>
  )
}

export default App

提示

使用规则

  1. 只能在组件中或者其他自定义Hook函数中调用
  2. 只能在组件的顶层调用,不能嵌套在if、for、其它的函数中