likes
comments
collection
share

React 个人学习笔记(1) -- 组件通信React组件篇 个人主页 我今年大三,学前端的同学可以和我互相交流下 组

作者站长头像
站长
· 阅读数 33

React组件篇

关于jsx的基本语法网上已经很多了,个人对vue比较熟悉,也在vue中使用过jsx语法这里就不再写一次了

个人主页

我今年大三,学前端的同学可以和我互相交流下

React 学习主要作为一个消遣,个人还是主Vue的,但是学习React也会坚持下去

组件通信

React组件使用props传参,跟vue差不多

function Home() {
  return (
    <img src="xxxx" alt="xxxx" width={500} height={500} />
  )
}

父子组件通信

编写一个子组件

function Test() {
  return <div>Hello World</div>
}

export default Test

在父组件中引入该组件

import Test from '@/components/Test'

function Home() {
  return (
    <Test></Test>
  )
}

export default Home
父传子

支持的类型: string等等等反正Vue支持的他也支持 还支持JSX.Elmenet

先声明props的类型 跟vuedefineProps差不多

这里声明组件类型把函数定义形式从function改成了箭头函数,不然我也不知道怎么定义,有机会看一下别人的代码

import type React from 'react'

interface Props {
  title: string
  id: number
  obj: {
    a: number
    b: string
  }
  arr: number[]
  cb: () => void
  empty: null
  element: JSX.Element
}

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

export default Test

在父组件中传参进行测试

<Test
      title="测试"
      id={1}
      obj={{ a: 1, b: '2' }}
      arr={[1, 2, 3]}
      empty={null}
      cb={() => {}}
      element={<div>element</div>}
    >
    </Test>

查看浏览器的控制台

React 个人学习笔记(1) -- 组件通信React组件篇 个人主页 我今年大三,学前端的同学可以和我互相交流下 组

现在对了

注意单向数据流, 不能直接修改Props里的数据

这点没啥问题

定义默认值

基本用法就是将属性变为可选的? 然后对porps进行解构然后赋值

import type React from 'react'

interface Props {
  title?: string
  id: number
  obj: {
    a: number
    b: string
  }
  arr: number[]
  cb: () => void
  empty: null
  element: JSX.Element
}

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

export default Test

还有一种方式是使用defaultProps

然后将defaultPropsProps进行合并

不过好麻烦,不适合我这种懒人klf

React.FC

就是函数式组件的类型,接收一个泛型为Props推导类型

FCFunction Component

Children

就跟vueslot 用法一样吧,这玩意应该是组件库用的多

import Test from '@/components/Test'

function Home() {
  return (
    <Test>
      <div>Rika</div>
    </Test>
  )
}

export default Home

要在子组件中手动声明children

好像是18之后才要手动声明的

import type React from 'react'

interface Props {
  children: React.ReactNode // 手动定义类型
}

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

export default Test

子传父

给子组件一个方法,跟vue一样

父组件

import Test from '@/components/Test'

function Home() {
  const fn = (params: string) => {
    console.log('触发父组件的事件,value:', params)
  }
  return (
    <Test cb={fn}></Test>
  )
}

export default Home

子组件

import type React from 'react'

interface Props {
  cb: (params: string) => void
}

const Test: React.FC<Props> = ({ cb }) => {
  return (
    <div>
      <button type="button" onClick={() => cb('Rika!')}>Click me</button>
    </div>
  )
}

export default Test

兄弟组件传值

原理是发布订阅模式

我之前手写了一个手写一个发布订阅模式吧!

不用原生浏览器也可以用mitt - npm (npmjs.com)

父组件引入两个兄弟组件

// react 没有全局组件局部组件的概念

import Test1 from '@/components/Test1'
import Test2 from '@/components/Test2'

function Home() {
  return (
    <>
      <Test1></Test1>
      <Test2></Test2>
    </>

  )
}

export default Home

第一个兄弟组件用于派发事件

import type React from 'react'

const Test1: React.FC = () => {
  const event = new Event('on-card')
  const clickHandler = () => {
    console.log(event)
    event.params = {
      name: 'Rika!',
    } // 事件参数
    window.dispatchEvent(event)
  }
  return (
    <div>
      <button type="button" onClick={clickHandler}>派发事件</button>
    </div>
  )
}

declare global {
  interface Event {
    params: any
  } // 这种应该抽离到全局声明文件中的吧 应该也许大概
}

export default Test1

第二个兄弟组件用于接收事件

import type React from 'react'

const Test2: React.FC = () => {
  window.addEventListener('on-card', e => console.log(e.params))
  return (
    <div>Test2</div>
  )
}

export default Test2

使用mitt
npm install --save mitt

增加一个EventBus的文件 我不知道具体要怎么创,按我的理解创了一个 位置src/EventBus/index.ts 应该不太规范 先用着

import type { Emitter } from 'mitt'
import mitt from 'mitt'

interface Events {
  'on-card': string
  [key: string]: unknown
  [key: symbol]: unknown
}

const emitter: Emitter<Events> = mitt<Events>()

export default emitter

除了事件的类型还要定义stringsymbol的索引签名,好麻烦,不知道是不是我使用方式的问题

第一个兄弟组件爆改为

import type React from 'react'
import emitter from '@/EventBus'

const Test1: React.FC = () => {
  const clickHandler = () => {
    emitter.emit('on-card', 'rika')
  }
  return (
    <div>
      <button type="button" onClick={clickHandler}>派发事件</button>
    </div>
  )
}

declare global {
  interface Event {
    params: any
  } // 这种应该抽离到全局声明文件中的吧 应该也许大概
}

export default Test1

第二个兄弟组件爆改为

import type React from 'react'
import emitter from '@/EventBus'

const Test2: React.FC = () => {
  emitter.on('on-card', e => console.log(e))
  return (
    <div>Test2</div>
  )
}

export default Test2

但是测试的时候发现mitt事件会触发两次,奇奇怪怪的

React 个人学习笔记(1) -- 组件通信React组件篇 个人主页 我今年大三,学前端的同学可以和我互相交流下 组

因为使用useEffect也会有事件触发两次的情况所以我尝试把react<StrictMode>注释掉,事件正常触发,问题解决

React 个人学习笔记(1) -- 组件通信React组件篇 个人主页 我今年大三,学前端的同学可以和我互相交流下 组

转载自:https://juejin.cn/post/7417474250595303462
评论
请登录