React第九章(组件通信)

组件通信Props

React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组和函数 以及html 元素,这样可以使我们的组件更加灵活。

例如我们在使用原生html标签时,我们可以为其传递属性,如下

html 复制代码
<img  width='500' height='500' alt='xxx' src='xxxxxxx'  />

那在React中,也允许将属性传递给自己编写的组件 如下

tsx 复制代码
export default function App(){
    return (<Card title='标题1' content='内容'></Card>)
}

父子组件通信

编写一个子组件 Test

tsx 复制代码
const Test = () => {
    return <div>Test</div>
}
export default Test 

在App.tsx 引入该子组件

tsx 复制代码
import Test from "./components/Test"
function App() {
  return (
    <>
      <Test></Test>
    </>
  )
}

export default App

1. 父向子组件传递 props

支持的类型如下:

  • string title={'测试'}
  • number id={1}
  • boolean isGirl={false}
  • null empty={null}
  • undefined empty={undefined}
  • object obj={ { a: 1, b: 2 } }
  • array arr={[1, 2, 3]}
  • function cb={(a: number, b: number) => a + b}
  • JSX.Element element={<div>测试</div>}
tsx 复制代码
function App() {
  return (
    <>
      <Test
        title={'测试'}
        id={1}
        obj={{ a: 1, b: 2 }}
        arr={[1, 2, 3]}
        cb={(a: number, b: number) => a + b}
        empty={null}
        element={<div>测试</div>}
        isGirl={false}
      >
      </Test>
    </>
  )
}

子组件接受父组件传递的props

props是一个对象,会作为函数的第一个参数接受传过来的props值

注意:我们需要遵守单向数据流,子组件不能直接修改父组件的props

在React源码中会使用Object.freeze冻结props,限制props的修改。

Object.freeze() 静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定

tsx 复制代码
import React from "react"
interface Props {
    title: string
    id: number
    obj: {
        a: number
        b: number
    }
    arr: number[]
    cb: (a: number, b: number) => number
    empty: null
    element: JSX.Element
}

const Test:React.FC<Props> = (props) => {
    console.log(props)
    return <div>Test</div>
}

export default Test 

2.定义默认值

第一种方式

将属性变为可选的这儿使用title举例 title?: string

然后将props进行解构,定义默认值 {title = '默认标题'}

tsx 复制代码
import React from "react"
interface Props {
    title?: string
    id: number
    obj: {
        a: number
        b: number
    }
    arr: number[]
    cb: (a: number, b: number) => number
    empty: null
    element: JSX.Element
}

const Test:React.FC<Props> = ({title = '默认标题'}) => {
    return <div>Test</div>
}

export default Test 
第二种方式

使用defaultProps进行默认值赋值,最后把defaultProps 和 props 合并,注意顺序要先写defaultProps,再写props 因为props会覆盖defaultProps的值。

tsx 复制代码
import React from "react"
interface Props {
    title?: string
    id: number
    obj: {
        a: number
        b: number
    }
    arr: number[]
    cb: (a: number, b: number) => number
    empty: null
    element: JSX.Element
}

const defaultProps: Partial<Props> = {
    title: '默认标题',
}

const Test: React.FC<Props> = (props) => {
    const { title } = { ...defaultProps, ...props }
    return <div>{title}</div>
}

export default Test 

3. React.FC

React.FC是函数式组件,是在TS使用的一个范型。FC是Function Component的缩写

React.FC 帮助我们自动推导Props的类型。

注意:在旧版本的React.FC是包含PropsWithChildren这个声明新版本已经没有了

3.props.children 特殊值

这个功能类似于Vue的插槽,直接在子组件内部插入标签会自动一个参数props.children

tsx 复制代码
function App() {
  return (
    <>
      <Test>
        <div>123</div>
      </Test>
    </>
  )
}

子组件使用children属性

在之前的版本children是不需要手动定义的,在18之后改为需要手动定义类型

这样就会把父级的 <div>123</div> 插入子组件的 <div> 里面

tsx 复制代码
import React from "react"
interface Props {
    children: React.ReactNode //手动声明children
}

const Test: React.FC<Props> = (props) => {
    return <div>{props.children}</div>
}

export default Test 
4.子组件给父组件传值

React没有像Vue那样的emit派发事件,所有我们回调函数模拟emit派发事件

父组件传递函数过去,其本质就是录用函数的回调

tsx 复制代码
import Test from "./components/Test"
function App() {
  const fn = (params:string) => {
    console.log('子组件触发了 父组件的事件',params)
  }
  return (
    <>
      <Test callback={fn}></Test>
    </>
  )
}

子组件接受函数,并且在对应的事件调用函数,回调参数回去

tsx 复制代码
import React from "react"
interface Props {
    callback: (params: string) => void
    children?: React.ReactNode
}

const Test: React.FC<Props> = (props) => {
    return <div>
        <button onClick={() => props.callback('我见过龙')}>派发事件</button>
    </div>
}

export default Test 

兄弟组件通信

定义两个组件放到一起作为兄弟组件,其原理就是发布订阅设计模式,发布订阅已经讲过无数次了这里不在阐述,原生浏览器已经实现了这个模式我们可以直接使用。

如果不想使用原生浏览器,可以使用mitt

mitt文档 www.npmjs.com/package/mit...

tsx 复制代码
import Card from "./components/Card"
import Test from "./components/Test"
function App() {

  return (
    <>
      <Test></Test>
      <Card></Card>
    </>
  )
}

export default App

第一个兄弟组件 定义事件模型

tsx 复制代码
import React from "react"
const Test: React.FC = (props) => {
    const event = new Event('on-card') //添加到事件中心
    const clickTap = () => {
        console.log(event)
        event.params = { name: '我见过龙' }
        window.dispatchEvent(event) //派发事件
    }
    return <div>
        <button onClick={clickTap}>派发事件</button>
    </div>
}
//扩充event类型
declare global {
    interface Event {
        params: any
    }
}

export default Test 

第二个兄弟组件接受事件

tsx 复制代码
import './index.css'
export default function Test2() {
    //接受参数
    window.addEventListener('on-card', (e) => {
        console.log(e.params, '触发了')
    })

    return <div className="card"></div>
}
相关推荐
OEC小胖胖4 分钟前
js中正则表达式中【exec】用法深度解读
开发语言·前端·javascript·正则表达式·web
有一个好名字16 分钟前
vue3路由
前端·vue.js
马卫斌 前端工程师32 分钟前
npm 源切换以及添加 使用工具 nrm 使用方法
前端·npm·node.js
小彭努力中37 分钟前
49. 建模软件绘制3D场景(Blender)
前端·3d·blender·webgl
任风雨1 小时前
JWT的基础与使用
前端·网络·安全
汪子熙2 小时前
CSS Style position: absolute 的含义
前端·css
晴天蜗牛不一般2 小时前
隆重的给大家介绍一下 <BaseEcharts/>
前端·npm·echarts
ceek@2 小时前
HTML增加复制模块(使用户快速复制内容到剪贴板)
前端·javascript·html
小于负无穷2 小时前
前端面试题(十)
前端
Tim20232 小时前
202409使用eslint与prettier的实战
前端