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>
}
相关推荐
我要洋人死1 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人1 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人1 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR1 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香1 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596931 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai2 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书
Gavin_9152 小时前
【JavaScript】模块化开发
前端·javascript·vue.js
懒大王爱吃狼3 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
小牛itbull4 小时前
ReactPress:重塑内容管理的未来
react.js·github·reactpress