React 个人学习笔记(1) -- 组件通信React组件篇 个人主页 我今年大三,学前端的同学可以和我互相交流下 组
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
的类型 跟vue
的defineProps
差不多
这里声明组件类型把函数定义形式从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>
查看浏览器的控制台
现在对了
注意单向数据流, 不能直接修改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
然后将defaultProps
和Props
进行合并
不过好麻烦,不适合我这种懒人klf
React.FC
就是函数式组件的类型,接收一个泛型为Props
推导类型
FC
即 Function Component
Children
就跟vue
的 slot
用法一样吧,这玩意应该是组件库用的多
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
除了事件的类型还要定义string
和symbol
的索引签名,好麻烦,不知道是不是我使用方式的问题
第一个兄弟组件爆改为
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事件会触发两次,奇奇怪怪的
因为使用useEffect
也会有事件触发两次的情况所以我尝试把react
的<StrictMode>
注释掉,事件正常触发,问题解决
转载自:https://juejin.cn/post/7417474250595303462