基本来说和之前的没有什么太大区别,之前一直用的vue,纯粹当复习一遍react了
快捷键
rsc --> 自动创建函数式组件
rsi --> 自动创建函数式组件且带props
rcc --> 自动创建类组件
类组件的props是自动存储到类的实例对象中了,可直接通过实例对象访问,也就是this.props.xxx
一 组件传参
1) 父传子
1 props (类组件使用this.props)
-单向传递,子组件只能接收无法反向修改
// 父组件
import ReactDom from 'react-dom/client'
import Progeny from './progeny' // 引入子组件
const App = () => { // 父组件jsx代码
// 注意传递函数需要传一个完整的函数,例如fun={ alert('参数') }会在子组件直接执行
return <div>
<Progeny test='传家宝' num={ 123 } fun={ () => alert('传递了一个函数') }/>
</div>
}
const root = ReactDom.createRoot(documnet.getElementById('root')) // 创建虚拟Dom
root.render(App) // 挂载写好的jsx结构
// 子组件
const Progeny = (props) => {
console.log(props) // 会打印一个包含test,num,fun的对象
props.fun && props.fun() // 执行父组件传递的函数
return <div>
{ props.test }有{ props.num }个
</div>
}
更新中。。。(肯定还有别的,暂时还没学到)
二 useState钩子
等同vue3中的ref,reactive作用一致
函数式组件
语法
1) 直接赋值
import { useState } from 'react'
const App = () => {
const [count, setCount] = useState(1)
const fun = () => { setCount(count + 1) }
return <div>
<button onClick={() => setCount(count - 1) }>-1</button>{ count }<button onClick={ fun }>+1</button>
</div>
}
修改state的值必须使用setter设置器,使用setter设置器修改变量时,会触发render重新渲染组件,⚠️ 注意修改之后必须有变化才会重新渲染,diff算法会前后进行对比,如果没变化就什么也不会做
⚠️ 另外setter是修改变量的值,但如果是定义的引用类型数据,需要改变堆内存的值,的确是不需要使用setter,但是页面不会重新渲染所以看起来好像没有生效,所以改变引用类型数据的时候通常改变完需要使用setter重新赋值一次(跟vue一样,并且需要浅拷贝一下)
⚠️ 最后,setter修改一个state时,并不是代表把当前的state改掉了,而是改变下一次渲染的state值,并且setter是异步的,所以使用setter之后打印state的值还是没改变之前的值
2) 另外还可以在括号里传一个回调函数
import { useState } from 'react'
const App = () => {
const counts = useState(1)
const count = counts[0]
const setCount = counts[1]
// 此种写法与上面[xx, setxx]作用完全一致,只是提醒一下useState的返回值是一个数组,上述写法其实是把数组给解构了
const fun = () => {
setTimeout(() => {
setCount(prev => prev + 1)
}, 1000)
}
return <div>
{
{ count }}
<button onClick={ fun }>按钮</button>
</div>
}
直接传回调与直接传值作用完全一样,只是两种写法的区别而已
⚠️ 但是setter是一种类似节流的机制,如果在很短时间之内多次触发,执行一次之后,在组件重新渲染之前,其他次都没有意义,因为state并没有实时改变,state + 1用的state一直是不变的,在大型项目里是可能出现问题的,当然使用回调也无法避免,所以react提供了回调函数的第一个参数是上一次state的值,使用该参数才会避免这种问题
类组件
类组件state同样也是放到state中了,但是仍旧与函数式组件有很大差异
语法
import React { Component } from 'react'
class App extends Component {
state = { // 类组件定义state语法,所有要使用的状态都放到这个对象里
count: 0
}
countHandler1 = () => { // 定义函数不需要const,其实就是定义一个类的方法
this.setState({ count: this.state.count + 1 })
// 类组件修改state时不需要浅靠谱原state,直接修改即可不会像,函数式组件那样覆盖没有修改的值
// 但是如果修改的是state里定义的一个对象仍旧需要浅拷贝,这其实跟小程序的语法很相似
}
countHandler2 = () = > { // 同样的可以使用回调
this.setState(prev => {
return { count: prev.count + 1 } // 有一点要注意prev是指的整个state
})
}
render() {
return <div>
{ this.state.count } // 访问时都是需要this的
<button onClick={ countHandler1 }>按钮</button>
<button onClick={ countHandler2 }></button>
</div>
}
}
三 获取Dom
函数式组件
1)直接使用原生的document对象获取
这里就不写了,总之react里可以直接使用documnet直接获取dom,但是不推荐,或多或少的会多耗费一点性能(获取dom这事本身就耗性能,react提供的方式也好点有限,尽可能避免操作dom)
2) 通过ref
const { useRef } from 'react'
const App = () => {
const divRef = useRef()
console.log(divRef) // 打印结果: { current: undefined }
const fun = () => {
console.log(divRef) // 打印结果: { current: div.div } 也就是dom元素
}
return <div>
<div ref={ divRef }></div>
<button onClick={ fun }>按钮</button>
</div>
}
同样的代码运行的时候还没有获取到,第一次渲染完才会吧dom赋值给选定的对象,current属性就是所需要操作的dom对象
⚠️ 这里ref只是提供一个存储用的对象,没有其他特殊的用途,自己创建一个{current: null}和useRef完全一致,两者的区别是自己创建的js对象每次渲染组件都会创建一次,会造成一些问题,而useRef创建的对象并不会随组件的创建而重新创建
❗所以useRef还有一个用途就是,如果需要一个随着组件更新不会改变的对象,就可以使用useRef
类组件
与函数式组件一致但是用的不是use了而是React.createRef(),原理类似,所以同样的,也可以自己创建一个空对象,不在赘述
import React , { Component } from 'react'
class App extends Component {
divRef = React.createRef()
divHandler = () => {
console.log(divRef)
}
render(){
return <div>
<div ref={ this.divRef }>这是一个类组件</div>
<button onClick={ divHandler }>查看dom元素</button>
</div>
}
}
更新中。。。。(白天还要上班,有时间才能更新)